diff --git a/README.md b/README.md index 6365debd..416f794b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,86 @@ -webogram -======== +## Webogram - Telegram UNOFFICIAL web application +================================================= -Telegram UNOFFICIAL web application, GPL v3 +Telegram offers great [apps for mobile communication](https://www.telegram.org). It is based on the [MTProto protocol](https://core.telegram.org/protocol) and has an [Open API](http://core.telegram.org/api). I personally like Telegram for its speed and cloud-support (that makes a web app possible, unlike in the case of WA and others). + +MTProto data can be carried over HTTP, but no official web-version for Telegram exists for the time being. So this project is my take at creating one. + + +> **Disclaimer**: +> This is an alpha version of the Telegram **UNOFFICIAL** web application. It may have undetected security issues, and there is definitely a load of bugs to fix, features to add and so on. So if you want 200% secure and fully functional communication, don't use this yet! You can always find Telegram official mobile applications here: https://telegram.org + +That said, I'm using this app myself and I'd like to share its sources, so anyone can contribute to the development. Any help is welcome! + + +### Interface + + +Here are some screenshots of the interface: + +[ To be added soon :) ] + +### Implemented functionality list + +* Sign in by phone number + SMS code (no calls supported yet) +* View list of existings chats (up-posting) with infinite scrolling +* View messages history for each chat/group (bottom-posting) with infinite scrolling +* View brief profile info +* View group info, members list +* View media in messages: photo, video +* Download documents from messages +* Emoji display in all browsers (Chrome, non-OSX ones) +* Emoji keyboard +* Send plain-text messages to user or group +* Send files (photos or documents) via attach icon or drag'n'drop + + +### Unsupported at the moment + +* Secret chats +* Create new group +* Edit group photo/title/participants +* Desktop notifications +* Settings +* Edit profile/userpic +* Contacts +* Edit, delete, forward messsages +* a lot more... + + +## Technical details + +The app is based on AngularJS JavaScript framework, written in pure JavaScript (migration to CoffeeScript is planned for the future). jQuery is used for DOM manipulations, and Bootstrap is the CSS-framework. + + +### Running locally + + +#### Running web-server + +Project repository is based on angularjs-seed and includes a simple web-server, so it's easy to launch the app locally on your desktop. +Install [node.js](http://nodejs.org/) and run `scripts/web-server.js`. Open page http://localhost:8000/app/index.html in your browser. + +#### Running as Chrome Packaged App + +It is possible to run this application in Chrome browser as a packaged app. In order to do this, open this URL in Chrome: `chrome://extensions/`, then tick "Developer mode" and press "Load unpacked extension...". Select the downloaded `app` folder and Webogram application should appear in the list. + + +### Third party libraries + +Besides frameworks mentioned above, other libraries are used for protocol and UI needs. Here is the short list: + +* [JSBN](http://www-cs-students.stanford.edu/~tjw/jsbn/) +* [CryptoJS](https://code.google.com/p/crypto-js/) +* [zlib.js](https://github.com/imaya/zlib.js) +* [UI Bootstrap](http://angular-ui.github.io/bootstrap/) +* [jQuery Emojiarea](https://github.com/diy/jquery-emojiarea) +* [nanoScrollerJS](https://github.com/jamesflorentino/nanoScrollerJS) +* [gemoji](https://github.com/github/gemoji) +* [emoji-data](https://github.com/iamcal/emoji-data) + +Many thanks to all these libraries' authors and contributors. Detailed list with descriptions and licenses is available [here](/app/vendors). + + +### Licensing + +The source code is licensed under GPL v3. License is available [here](/LICENSE). \ No newline at end of file diff --git a/app/css/app.css b/app/css/app.css new file mode 100644 index 00000000..c16bef1b --- /dev/null +++ b/app/css/app.css @@ -0,0 +1,1162 @@ +/* app css stylesheet */ + +html { + background: #dee4e9 url(../img/bg_tile.png?1) 0 0 repeat; + /*background: #dee4e9 url(../img/bg_full.png) 0 0 no-repeat;*/ + /*background-size: cover;*/ + /*background-size: contain;*/ + /*background-size: 248px 382px;*/ +} +body { + background: none; + + /*font: 12px/18px "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;*/ + /*font: 12px/18px Arial, "Lucida Grande", "Lucida Sans Unicode", Arial, Helvetica, Verdana, sans-serif;*/ + font: 12px/18px "Lucida Grande", "Lucida Sans Unicode", Arial, Helvetica, Verdana, sans-serif; + -webkit-font-smoothing: antialiased; +} +a { + color: #3a6d99; +} +a:hover { + color: #3a6d99; +} +a:hover { + cursor: pointer; +} +.form-control { + border: 1px solid #d9dbde; + border-radius: 2px; + -webkit-box-shadow: none; + box-shadow: none; + -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; + transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; +} + +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); +} + +.form-control:-moz-placeholder { + color: #9aa2ab; +} +.form-control::-moz-placeholder { + color: #9aa2ab; +} +.form-control:-ms-input-placeholder { + color: #9aa2ab; +} +.form-control::-webkit-input-placeholder { + color: #9aa2ab; +} + + +.btn-tg { + color: #ffffff; + background-color: #6AC065; + /*58b152*/ + border-color: #6AC065; +} + +.btn-tg:hover, +.btn-tg:focus, +.btn-tg:active, +.btn-tg.active, +.open .dropdown-toggle.btn-tg { + color: #ffffff; + background-color: #61b75b; + border-color: #61b75b; +} + +.btn-tg:active, +.btn-tg.active, +.open .dropdown-toggle.btn-tg { + background: #5aaf54; + background-image: none; +} + +.btn-tg.disabled, +.btn-tg[disabled], +fieldset[disabled] .btn-tg, +.btn-tg.disabled:hover, +.btn-tg[disabled]:hover, +fieldset[disabled] .btn-tg:hover, +.btn-tg.disabled:focus, +.btn-tg[disabled]:focus, +fieldset[disabled] .btn-tg:focus, +.btn-tg.disabled:active, +.btn-tg[disabled]:active, +fieldset[disabled] .btn-tg:active, +.btn-tg.disabled.active, +.btn-tg[disabled].active, +fieldset[disabled] .btn-tg.active { + background-color: #999; + border-color: #999; +} + +.font-light { + font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Light", Helvetica, Arial , Verdana, sans-serif; + font-weight: 300; +} + +.tg_page_head .container { + display: block; + width: auto; + padding: 0; +} +.tg_page_head .navbar-inverse { + /*-webkit-app-region: drag;*/ + background: #497495; + border: 0; + + -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.11); + -moz-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.11); + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.11); + + margin: 0; +} +.tg_page_head .navbar > .container .navbar-brand { + padding: 9px; + opacity: 0.9; + margin-left: 0; + -webkit-transition: opacity swing .9s; +} + +.tg_page_head .navbar > .container .navbar-brand-alpha { + color: #FFFFFF; + font-size: 12px; + padding-left: 5px; +} + +.tg_head_logo { + background: url(../img/Logo_2x.png) 0 0 no-repeat; + background-size: 110px 31px; + display: inline-block; + width: 110px; + height: 31px; +} + +.tg_page_head .navbar > .container .navbar-brand:hover { + opacity: 1; +} + +.tg_page_head .navbar-inverse .navbar-nav > li > a { + color: #b9cfe3; + font-size: 13px; +} +.tg_page_head .navbar-inverse .navbar-nav > li > a:hover { + color: #FFF; +} + +.tg_progress { + height: 12px; + margin: 0; + padding: 0; + background: rgba(255,255,255, 0.4); + border: 5px solid rgba(0,0,0, 0.5); + border-radius: 3px; +} +.tg_progress .progress-bar { + height: 2px; + line-height: 2px; + background: rgba(255,255,255, 0.9); + border-radius: 2px; + overflow: hidden; +} + +.modal-content { + border-radius: 4px; + -webkit-box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); +} +.modal_close_wrap { + cursor: pointer; + position: fixed; + top: 0; + right: 0; + width: 50%; + height: 100%; +} +.modal_close { + background: url(../img/icons/CloseHover_2x.png) 0 0 no-repeat; + background-size: 33px 33px; + width: 33px; + height: 33px; + float: right; + margin: 60px 10px 0 0; + opacity: 0.5; + + -webkit-transition : .2s; + -moz-transition : .2s; + -o-transition : .2s; + transition : .2s; +} +.modal_close_wrap:hover .modal_close { + opacity: 1; +} + +.modal-header { + padding: 12px 0 4px 3px; + border-bottom: 2px solid #E1E1E1; + margin: 0 18px; +} +.modal-title { + font-weight: bold; + font-size: 17px; + line-height: 1.4; +} + +.modal-close-link { + font-size: 12px; + line-height: 1.4; + float: right; + padding: 0 2px 0; + margin: 6px 2px 0 0; +} +.modal-close-link:hover { + text-decoration: none; +} + + +.img_fullsize_with_progress_wrap { + position: relative; + /*margin: 0 auto 20px;*/ + margin: 0 auto; +} +.img_fullsize_progress_overlay { + position: absolute; + width: 100%; + height: 100%; +} +.img_fullsize_progress_wrap { + background: rgba(0,0,0, .1); + position: relative; +} +.img_fullsize_progress { + position: absolute; + bottom: 15px; + left: 50%; + width: 190px; + margin-left: -95px; +} + + +/* Welcome */ +.jumbotron { + background: none; +} + +/* Login page */ +.login_form_wrap { + max-width: 310px; + padding: 25px; + background: #FFF; + margin: 200px auto 0; + border-radius: 3px; + overflow: hidden; + + -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); +} +.login_form_head { + color: #222222; + margin-top: 0; + text-align: center; +} +.login_form_lead { + color: #959595; + text-align: center; + margin: 15px 0 30px; + font-size: 13px; +} + + +/* IM page start */ + + + +.im_page_wrap { + background: #FFF; + max-width: 1000px; + margin: 0 auto; + + -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); + margin-bottom: 40px; + + border-radius: 0 0 3px 3px; + overflow: hidden; +} + +.im_dialogs_col_wrap { + float: left; + width: 310px; + border-right: 2px solid #E9EBED; + padding-bottom: 10px; +} + +.im_history_col_wrap { + float: left; + width: 690px; +} + + +/* Dialogs list */ + +.im_dialogs_col .nano > .pane { + background : rgba(0,0,0,.0); + width : 12px; + right: -7px; + -webkit-transition : .2s; + -moz-transition : .2s; + -o-transition : .2s; + transition : .2s; + -moz-border-radius : 0; + -webkit-border-radius : 0; + border-radius : 0; +} +.im_dialogs_col .nano > .pane > .slider { + background: #A5B1B9; + margin: 0 5px; + -moz-border-radius : 0; + -webkit-border-radius : 0; + border-radius : 0; +} + +.im_dialogs_search { + padding: 14px 12px; + /*border-right: 2px solid #E9EBED;*/ +} +.im_dialogs_search_field { + font-size: 12px; + line-height: normal; + background: #F2F2F2 url(../img/icons/Search_2x.png) 7px 9px no-repeat; + background-size: 15px 14px; + border: 1px solid #F2F2F2; + border-radius: 3px; + padding: 6px 6px 6px 30px; + margin-bottom: 0; + margin: 0; +} +.im_dialogs_search_field:focus, +.im_dialogs_search_field:active { + background-color: #FFF; +} + + + +.im_dialogs_wrap { + overflow: visible; + overflow-x: visible !important; + overflow-y: visible; +} +.im_dialogs_scrollable_wrap { + /*border-right: 2px solid #E9EBED;*/ + padding: 0 12px; + outline: none ! important; + overflow-x: visible; +} +.im_dialogs_scrollable_wrap .nav-stacked > li + li { + margin-top: 0; + margin-left: 0; +} + +.im_dialogs_scrollable_wrap a.im_dialog { + color: #000; + padding: 8px 9px; + border-radius: 0; + border-bottom: 1px solid #FFF; +} +.im_dialogs_scrollable_wrap li:last-child a.im_dialog { + border-bottom: 1px solid #FFF; +} + +.im_dialogs_scrollable_wrap a.im_dialog:hover, +.im_dialogs_scrollable_wrap .active a.im_dialog { + margin-top: -1px; + overflow: hidden; +} +.im_dialogs_scrollable_wrap a.im_dialog:hover { + background: #f2f6fa; + border-top: 1px solid #f2f6fa; + border-bottom-color: #f2f6fa; +} +.im_dialogs_scrollable_wrap .active a.im_dialog { + border-radius: 2px; + background-color: #5785A5; + border-top: 1px solid #5785A5; + border-bottom-color: #5785A5; +} +.im_dialogs_scrollable_wrap .active a.im_dialog:hover { + background-color: #5785A5; +} +.im_dialogs_scrollable_wrap li:first-child a.im_dialog, +.im_dialogs_scrollable_wrap .active + li > a.im_dialog { + margin-top: 0; + border-top: 0; +} + +.im_dialogs_scrollable_wrap a.im_dialog .icon, +.im_dialogs_scrollable_wrap a.im_dialog .glyphicon { + display: none; +} + +.im_dialog_message_wrap { + overflow: hidden; + word-wrap: break-word; +} +.im_dialog_chat_from_wrap, +.im_dialog_message_media, +.im_dialog_message_service { + color: #3a6d99; +} +.im_dialog_message_text { + color: #808080; +} +a.im_dialog:hover .im_dialog_message_text { + color: #698192; +} +.active a.im_dialog .im_dialog_chat_from_wrap, +.active a.im_dialog .im_dialog_message_media, +.active a.im_dialog .im_dialog_message_service, +.active a.im_dialog .im_dialog_message_text { + color: #FFF; +} +.im_dialog_photo { + width: 40px; + height: 40px; + border-radius: 2px; + overflow: hidden; + margin: 0 10px 0 0; + +} +.im_dialog_peer { + font-weight: bold; + margin-top: 2px; + margin-bottom: 2px; +} + +.im_dialog_badge { + background: #75BB72; + border-radius: 2px; + font-size: 10px; + padding: 3px 4px; + margin-top: 4px; +} +.active .im_dialog_badge { + color: #428bca; + background-color: #fff; +} +.im_dialog_date { + font-size: 0.8em; + visibility: hidden; +} + +.im_dialog_service { + font-style: italic; + color: #999; +} +.im_dialog_message, +.im_dialog_peer { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.icon-group { + display: inline-block; + width: 18px; + height: 12px; + margin-top: 3px; + line-height: 14px; + vertical-align: text-top; + background: url(../img/icons/DialogListGroupChatIcon@2x.png) 0 0 no-repeat; + background-size: 18px 12px; +} +.active .icon-group { + background-image: url(../img/icons/DialogListGroupChatIcon_Highlighted@2x.png); +} + +/* IM history */ +.im_history_col { + padding: 0 8px 0 15px; +} + +.im_history_col .nano > .pane { + /*background : rgba(0,0,0,.0);*/ + background: #E9EBED; + width : 9px; + top: 10px; + /*margin-top: 10px;*/ + /*bottom: */ + -webkit-transition : .2s; + -moz-transition : .2s; + -o-transition : .2s; + transition : .2s; + -moz-border-radius : 2px; + -webkit-border-radius : 2px; + border-radius : 2px; +} +.im_history_col .nano > .pane > .slider { + background: #B3BFC7; + margin: 0; + -moz-border-radius : 2px; + -webkit-border-radius : 2px; + border-radius : 2px; +} + +.im_history_panel_wrap { + position: relative; + -webkit-box-shadow: 0px 2px 0px rgba(0, 0, 0, 0.12); + -moz-box-shadow: 0px 2px 0px rgba(0, 0, 0, 0.12); + box-shadow: 0px 2px 0px rgba(0, 0, 0, 0.12); + margin-right: 15px; +} +.im_history_panel { + padding: 10px 4px 0; +} +.im_history_panel_title h4 { + color: #333333; + margin-bottom: 7px; + font-size: 17px; +} +.im_history_panel_title h4 small { + color: #999; + font-size: 13px; + margin-left: 5px; +} +.im_history_panel_info_link { + /*color: #999;*/ + font-size: 13px; + font-weight: normal; + padding-top: 5px; + line-height: 1; +} +.im_history_panel_info_link:hover { + text-decoration: none; +} + + +.im_history_wrap { + overflow: hidden; + /*overflow-y: scroll;*/ +} +.im_history_scrollable_wrap { + outline: none ! important; + -webkit-user-select: text; +} + +.im_history_to_bottom { + position: relative; +} +.im_history_to_bottom .im_history_scrollable { + position: absolute; + bottom: 0; + width: 100%; +} +.im_history { + padding: 20px 0 0 3px; + /*max-width: 555px;*/ + max-width: 500px; + margin: 0 auto; +} + +.im_history_typing_wrap { + margin-top: 13px; + height: 18px; + line-height: 18px; + width: 100%; + margin-bottom: 13px; + overflow: hidden; +} +.im_history_typing { + font-size: 11px; + color: #999; + max-width: 495px; + margin: 0 auto; + + padding: 0 40px 0 47px; +} + +/*.im_history_typing { + -webkit-transition:all swing .2s; + -moz-transition:all swing .2s; + -ms-transition:all swing .2s; + -o-transition:all swing .2s; + transition:all swing .2s; +} +.im_history_typing.ng-enter { + opacity: 0; +} +.im_history_typing.ng-enter.ng-enter-active { + opacity: 1; +} +.im_history_typing.ng-leave { + opacity: 1; +} +.im_history_typing.ng-leave.ng-leave-active { + opacity: 0; +} + + +.im_history_message_wrap { + -webkit-transition:all swing .2s; + -moz-transition:all swing .2s; + -ms-transition:all swing .2s; + -o-transition:all swing .2s; + transition:all swing .2s; +} +.im_history_message_wrap.ng-enter { + position: relative; + bottom: -100px; + overflow: hidden; + opacity: 0; +} +.im_history_message_wrap.ng-enter.ng-enter-active { + bottom: 0; + opacity: 1; +} +.im_history_message_wrap.ng-leave { + opacity: 1; +} +.im_history_message_wrap.ng-leave.ng-leave-active { + opacity: 0; +}*/ + + + +.im_message_author { + color: #3a6d99; + font-weight: bold; +} + +.im_message_from_photo, +.im_message_contact_photo { + width: 34px; + height: 34px; + + border-radius: 2px; + overflow: hidden; +} +a.im_message_from_photo, +a.im_message_contact_photo { + margin: 1px 12px 0 0; +} +.im_message_contact_name { + color: #3C6E97; + font-weight: bold; +} +a.im_message_photo_thumb, +a.im_message_video_thumb { + display: block; + margin-top: 5px; + overflow: hidden; + border-radius: 2px; +} +img.im_message_photo_thumb, +img.im_message_video_thumb { + overflow: hidden; + border-radius: 2px; +} + +div.im_message_video_thumb { + position: relative; +} +.im_message_video_duration_wrap { + background: rgba(0, 0, 0, 0.5); + color: #FFF; + position: absolute; + margin-top: -15px; + height: 15px; + padding: 0 3px; + font-size: 11px; + line-height: 15px; + + border-radius: 0 0 2px 2px; + overflow: hidden; +} +.im_message_video_duration { + +} + +.im_message_geopoint { + border-radius: 2px; + margin-top: 5px; + overflow: hidden; + display: block; + position: relative; + width: 200px; + height: 100px; +} +.icon-geo-point { + position: absolute; + display: inline-block; + top: 50%; + left: 50%; + margin-left: -5px; + margin-top: -7px; + width: 10px; + height: 14px; + + background: url(../img/icons/Location_Active.png) 0 0 no-repeat; + background-size: 10px 14px; +} + + + +.im_message_document { + margin-top: 3px; + border-radius: 3px; + display: inline-block; + line-height: 0; +} +.icon-document { + display: inline-block; + width: 38px; + height: 38px; + vertical-align: text-top; + background: #F2F2F2 url(../img/icons/DocGrey_2x.png) 8px 10px no-repeat; + background-size: 20px 20px; + border-radius: 3px; + margin-right: 0; +} +.im_message_document .icon-group { + background-image: url(../img/icons/DialogListGroupChatIcon_Highlighted@2x.png); +} +.im_message_document .im_message_document_name { + color: #999; + vertical-align: text-top; + display: inline-block; + line-height: 20px; + padding: 9px 5px 9px 0; + max-width: 200px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.im_message_document:hover, +.im_message_document:hover .icon-document { + background: #EBF0F5; + text-decoration: none; +} +.im_message_document:hover .icon-document { + background: #EBF0F5 url(../img/icons/DocBlue_2x.png) 8px 10px no-repeat; + background-size: 20px 20px; +} +.im_message_document:hover .im_message_document_name { + color: #698192; +} +.im_message_document_name strong { + color: #000; + padding-right: 3px; +} + + +.im_service_message_wrap { + text-align: center; +} +.im_service_message { + display: inline-block; + min-width: 10px; + padding: 4px 7px; + line-height: 1.4; + color: #999; + text-align: center; + border-radius: 10px; + margin: 5px 0; +} + +.im_service_message_photo_thumb { + display: block; + width: 100px; + margin: 0 auto; +} + + + +.im_content_message_wrap { + margin: 10px 0 5px; +} +.icon-message-status-unread { + background: #43A4DB; + border: 1px solid #FFF; + display: block; + width: 11px; + height: 11px; + border-radius: 5px; + overflow: hidden; + position: absolute; + margin-left: -27px; + margin-top: 14px; +} +.icon-message-status-tick { + /*display: inline-block;*/ + display: none; + width: 16px; + height: 10px; + background: url(../img/icons/Checks2_2x.png?1) 0 0 no-repeat; + background-size: 16px 10px; + top: 2px; + position: relative; +} +.icon-message-status-tick.message-status-unread-tick { + /*width: 13px;*/ + background: url(../img/icons/Checks1_2x.png?1) 0 0 no-repeat; + background-size: 16px 10px; +} +.im_message_date { + color: #adadad; + font-size: 0.9em; + /*font-size: 0.8em;*/ +} +div.im_message_author, +div.im_message_body { + border-radius: 2px; + display: block; + overflow: hidden; +} + +.im_message_text { + word-wrap: break-word; +} + +span.emoji { + display: -moz-inline-box; + -moz-box-orient: vertical; + display: inline-block; + vertical-align: baseline; + *vertical-align: auto; + *zoom: 1; + *display: inline; + height: 18px; + width: 18px; + background-size: 18px; + background-repeat: no-repeat; + text-indent: -9999px; +} + +.im_history_not_selected { + text-align: center; + color: #999; + font-size: 1.5em; + padding: 200px 50px 0; +} + +.im_send_form_wrap { + /*width: 581px;*/ + width: 526px; + margin: 0 auto; + padding: 10px 12px 22px 0; +} +.im_send_form { + /*width: 444px;*/ + width: 389px; + float: left; +} +.im_submit { + padding: 5px 12px; + font-size: 13px; + line-height: 17px; +} + +.im_send_dropbox_wrap { + background: #FFF; + display: none; + padding: 15px 10px; + margin: 1px; + border-radius: 4px; + overflow: hidden; + text-align: center; + color: #999; + position: absolute; +} +textarea.im_message_field { + font-size: 12px; + margin-bottom: 10px; + padding: 6px; + min-height: 50px; + height: 50px; + resize: none; +} +.im_attach { + cursor: pointer; + display: block; + overflow: hidden; + position: relative; + padding: 0 2px; + + width: 23px; + height: 23px; + margin-top: 4px; +} + +.icon-paperclip { + display: inline-block; + width: 19px; + height: 22px; + vertical-align: text-top; + background: url(../img/icons/Attach_2x.png) 0 0 no-repeat; + background-size: 19px 22px; +} +.im_attach:hover .icon-paperclip { + background-image: url(../img/icons/Attach_pressed_2x.png); +} + +.im_emoji_btn { + cursor: pointer; + padding: 0 2px; + + width: 23px; + height: 23px; + margin-top: 4px; + margin-left: 15px; +} +.icon-emoji { + display: inline-block; + width: 22px; + height: 22px; + vertical-align: text-top; + background: url(../img/icons/Smile_2x.png) 0 0 no-repeat; + background-size: 22px 22px; +} +.im_emoji_btn:hover .icon-emoji { + background-image: url(../img/icons/Smile_pressed_2x.png); +} + +.im_attach_input { + cursor: pointer; + font-size: 72px !important; + /*visibility: hidden;*/ + opacity: 0.01; + position: absolute; + z-index: 100; + margin: 0; + padding: 0; + + right: 0; +} + +.im_panel_peer_photo, +.im_panel_own_photo { + width: 50px; + height: 50px; + border-radius: 3px; + overflow: hidden; +} +div.im_panel_peer_photo { + cursor: pointer; + margin-left: 12px; + height: 55px; +} +div.im_panel_own_photo { + margin-right: 12px; +} + +.im_panel_peer_online { + background: #6DBF69; + border: 1px solid #FFF; + display: block; + width: 11px; + height: 11px; + border-radius: 5px; + overflow: hidden; + position: absolute; + margin-top: -7px; + margin-left: 43px; +} + + +.media_modal_wrap .modal-body { + padding: 19px 18px 17px; +} +a.img_fullsize { + display: block; + text-align: center; +} +img.img_fullsize { + margin: 0 auto; +} +.media_modal_info { + color: #777; + margin: 20px 0 0; +} +.media_modal_author { + font-weight: bold; +} + +.user_modal_window .modal-dialog { + padding-top: 150px; + max-width: 506px; +} +.user_modal_wrap .modal-body { + padding: 23px 25px 70px; +} +.user_modal_image_wrap { + width: 120px; + margin-right: 22px; +} +.user_modal_image { + width: 120px; + height: 120px; +} +.user_modal_header { + margin: 0 0 5px; +} +.user_modal_status { + color: #999; +} +.user_modal_send_btn { + padding-left: 0; + padding-right: 0; + font-size: 12px; + margin-top: 8px; +} + + +.chat_modal_window .modal-dialog { + max-width: 506px; +} +.chat_modal_wrap .modal-body { + padding: 23px 25px 15px; +} +.chat_modal_image_wrap { + width: 120px; + margin-right: 22px; +} +.chat_modal_image { + width: 120px; + height: 120px; +} +.chat_modal_header { + margin: 0 0 5px; +} +.chat_modal_members_count { + color: #999; +} +.chat_modal_invite_btn { + padding-left: 0; + padding-right: 0; + font-size: 12px; + margin-top: 8px; +} + +.chat_modal_members_header { + margin-top: 15px; +} + +.chat_modal_participant_wrap { + padding: 8px 7px; + border-top: 1px solid #E0E0E0; +} +.chat_modal_participant_name { + color: #3C6E97; + font-weight: bold; + margin: 4px 0 5px; +} +.chat_modal_participant_status { + color: #999; +} +.chat_modal_participant_photo { + width: 50px; + height: 50px; + margin-right: 10px; + overflow: hidden; +} + + + + + +/* Emoji area */ +.emoji-wysiwyg-editor:empty:before{ + content:attr(placeholder); + color: #9aa2ab; +} + +.emoji-wysiwyg-editor { + font-size: 12px; + margin-bottom: 10px; + padding: 6px; + min-height: 50px; + height: 50px; + resize: none; + overflow: auto; + + border: 1px solid #d9dbde; + border-radius: 2px; + -webkit-box-shadow: none; + box-shadow: none; + -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; + transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; +} +.emoji-wysiwyg-editor img { + width: 20px; + height: 20px; + vertical-align: middle; + margin: -3px 0 0 0; +} +.emoji-menu { + position: absolute; + z-index: 999; + width: 180px; + padding: 5px 2px 5px 5px; + margin-left: -88px; + margin-top: -225px; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + background: rgba(0,0,0, 0.7); + overflow: hidden; +} +.emoji-menu .emoji-items-wrap { + position: relative; + height: 190px; +} +.emoji-menu .emoji-items { + padding-right: 8px; +} +.emoji-menu img { + width: 20px; + height: 20px; + vertical-align: middle; + border: 0 none; +} +.emoji-menu a { + margin: -1px 0 0 -1px; + /*border: 1px solid #f2f2f2;*/ + padding: 4px; + display: block; + float: left; + border-radius: 2px; +} +.emoji-menu a:hover { + background-color: rgba(0,0,0, 0.5); + /*background-color: #fffae7;*/ +} +.emoji-menu:after { + content: ' '; + display: block; + clear: left; +} +.emoji-menu a .label { + display: none; +} + + +.emoji-menu .nano > .pane { + background : rgba(255,255,255,.0); +} +.emoji-menu .nano > .pane > .slider { + background: rgba(255,255,255,0.4); + /*background: #A5B1B9;*/ + /*margin: 0 5px;*/ + /*-moz-border-radius : 0; + -webkit-border-radius : 0; + border-radius : 0;*/ +} \ No newline at end of file diff --git a/app/img/Logo_1x.png b/app/img/Logo_1x.png new file mode 100755 index 00000000..f099252d Binary files /dev/null and b/app/img/Logo_1x.png differ diff --git a/app/img/Logo_2x.png b/app/img/Logo_2x.png new file mode 100755 index 00000000..f93dd4ec Binary files /dev/null and b/app/img/Logo_2x.png differ diff --git a/app/img/bg_full.png b/app/img/bg_full.png new file mode 100644 index 00000000..30c00429 Binary files /dev/null and b/app/img/bg_full.png differ diff --git a/app/img/bg_tile.png b/app/img/bg_tile.png new file mode 100644 index 00000000..bbd0b408 Binary files /dev/null and b/app/img/bg_tile.png differ diff --git a/app/img/icons/Arrow_1x.png b/app/img/icons/Arrow_1x.png new file mode 100755 index 00000000..58648875 Binary files /dev/null and b/app/img/icons/Arrow_1x.png differ diff --git a/app/img/icons/Arrow_2x.png b/app/img/icons/Arrow_2x.png new file mode 100755 index 00000000..8f53434c Binary files /dev/null and b/app/img/icons/Arrow_2x.png differ diff --git a/app/img/icons/Attach_1x.png b/app/img/icons/Attach_1x.png new file mode 100755 index 00000000..3842b4f9 Binary files /dev/null and b/app/img/icons/Attach_1x.png differ diff --git a/app/img/icons/Attach_2x.png b/app/img/icons/Attach_2x.png new file mode 100755 index 00000000..2f9a2ed9 Binary files /dev/null and b/app/img/icons/Attach_2x.png differ diff --git a/app/img/icons/Attach_pressed_1x.png b/app/img/icons/Attach_pressed_1x.png new file mode 100755 index 00000000..9c3cc6bb Binary files /dev/null and b/app/img/icons/Attach_pressed_1x.png differ diff --git a/app/img/icons/Attach_pressed_2x.png b/app/img/icons/Attach_pressed_2x.png new file mode 100755 index 00000000..0b814d22 Binary files /dev/null and b/app/img/icons/Attach_pressed_2x.png differ diff --git a/app/img/icons/CheckIn_Recent.png b/app/img/icons/CheckIn_Recent.png new file mode 100755 index 00000000..6cee6a83 Binary files /dev/null and b/app/img/icons/CheckIn_Recent.png differ diff --git a/app/img/icons/Checks1_1x.png b/app/img/icons/Checks1_1x.png new file mode 100755 index 00000000..35b72dec Binary files /dev/null and b/app/img/icons/Checks1_1x.png differ diff --git a/app/img/icons/Checks1_2x.png b/app/img/icons/Checks1_2x.png new file mode 100644 index 00000000..86c6f6a8 Binary files /dev/null and b/app/img/icons/Checks1_2x.png differ diff --git a/app/img/icons/Checks2_1x.png b/app/img/icons/Checks2_1x.png new file mode 100755 index 00000000..5ee5c1cb Binary files /dev/null and b/app/img/icons/Checks2_1x.png differ diff --git a/app/img/icons/Checks2_2x.png b/app/img/icons/Checks2_2x.png new file mode 100644 index 00000000..233b8282 Binary files /dev/null and b/app/img/icons/Checks2_2x.png differ diff --git a/app/img/icons/CloseHover_1x.png b/app/img/icons/CloseHover_1x.png new file mode 100755 index 00000000..3f319431 Binary files /dev/null and b/app/img/icons/CloseHover_1x.png differ diff --git a/app/img/icons/CloseHover_2x.png b/app/img/icons/CloseHover_2x.png new file mode 100755 index 00000000..ca9c4231 Binary files /dev/null and b/app/img/icons/CloseHover_2x.png differ diff --git a/app/img/icons/Close_1x.png b/app/img/icons/Close_1x.png new file mode 100755 index 00000000..3e6f6835 Binary files /dev/null and b/app/img/icons/Close_1x.png differ diff --git a/app/img/icons/Close_2x.png b/app/img/icons/Close_2x.png new file mode 100755 index 00000000..1a892be1 Binary files /dev/null and b/app/img/icons/Close_2x.png differ diff --git a/app/img/icons/DialogListGroupChatIcon@2x.png b/app/img/icons/DialogListGroupChatIcon@2x.png new file mode 100644 index 00000000..14c0e1fd Binary files /dev/null and b/app/img/icons/DialogListGroupChatIcon@2x.png differ diff --git a/app/img/icons/DialogListGroupChatIcon_Highlighted@2x.png b/app/img/icons/DialogListGroupChatIcon_Highlighted@2x.png new file mode 100644 index 00000000..4991d5bd Binary files /dev/null and b/app/img/icons/DialogListGroupChatIcon_Highlighted@2x.png differ diff --git a/app/img/icons/DocBlue_1x.png b/app/img/icons/DocBlue_1x.png new file mode 100755 index 00000000..6a85c564 Binary files /dev/null and b/app/img/icons/DocBlue_1x.png differ diff --git a/app/img/icons/DocBlue_2x.png b/app/img/icons/DocBlue_2x.png new file mode 100755 index 00000000..c85797b5 Binary files /dev/null and b/app/img/icons/DocBlue_2x.png differ diff --git a/app/img/icons/DocGrey_1x.png b/app/img/icons/DocGrey_1x.png new file mode 100755 index 00000000..8835c3b4 Binary files /dev/null and b/app/img/icons/DocGrey_1x.png differ diff --git a/app/img/icons/DocGrey_2x.png b/app/img/icons/DocGrey_2x.png new file mode 100755 index 00000000..7bcc7642 Binary files /dev/null and b/app/img/icons/DocGrey_2x.png differ diff --git a/app/img/icons/Location_Active.png b/app/img/icons/Location_Active.png new file mode 100755 index 00000000..9878efba Binary files /dev/null and b/app/img/icons/Location_Active.png differ diff --git a/app/img/icons/Logo_1x.png b/app/img/icons/Logo_1x.png new file mode 100755 index 00000000..f099252d Binary files /dev/null and b/app/img/icons/Logo_1x.png differ diff --git a/app/img/icons/Logo_2x.png b/app/img/icons/Logo_2x.png new file mode 100755 index 00000000..f93dd4ec Binary files /dev/null and b/app/img/icons/Logo_2x.png differ diff --git a/app/img/icons/NoResults.png b/app/img/icons/NoResults.png new file mode 100755 index 00000000..9b6747ec Binary files /dev/null and b/app/img/icons/NoResults.png differ diff --git a/app/img/icons/Search_1x.png b/app/img/icons/Search_1x.png new file mode 100755 index 00000000..480d46f3 Binary files /dev/null and b/app/img/icons/Search_1x.png differ diff --git a/app/img/icons/Search_2x.png b/app/img/icons/Search_2x.png new file mode 100755 index 00000000..e920e66e Binary files /dev/null and b/app/img/icons/Search_2x.png differ diff --git a/app/img/icons/Smile_1x.png b/app/img/icons/Smile_1x.png new file mode 100755 index 00000000..29c057a3 Binary files /dev/null and b/app/img/icons/Smile_1x.png differ diff --git a/app/img/icons/Smile_2x.png b/app/img/icons/Smile_2x.png new file mode 100755 index 00000000..f6103f12 Binary files /dev/null and b/app/img/icons/Smile_2x.png differ diff --git a/app/img/icons/Smile_pressed_1x.png b/app/img/icons/Smile_pressed_1x.png new file mode 100755 index 00000000..43c0e8a2 Binary files /dev/null and b/app/img/icons/Smile_pressed_1x.png differ diff --git a/app/img/icons/Smile_pressed_2x.png b/app/img/icons/Smile_pressed_2x.png new file mode 100755 index 00000000..a9cfc56f Binary files /dev/null and b/app/img/icons/Smile_pressed_2x.png differ diff --git a/app/img/icons/VideoIcon.png b/app/img/icons/VideoIcon.png new file mode 100755 index 00000000..ea9482b4 Binary files /dev/null and b/app/img/icons/VideoIcon.png differ diff --git a/app/img/icons/icon128.png b/app/img/icons/icon128.png new file mode 100644 index 00000000..34891d84 Binary files /dev/null and b/app/img/icons/icon128.png differ diff --git a/app/img/icons/icon16.png b/app/img/icons/icon16.png new file mode 100644 index 00000000..249892e1 Binary files /dev/null and b/app/img/icons/icon16.png differ diff --git a/app/img/placeholders/DialogListAvatarSystem@2x.png b/app/img/placeholders/DialogListAvatarSystem@2x.png new file mode 100644 index 00000000..305e86cf Binary files /dev/null and b/app/img/placeholders/DialogListAvatarSystem@2x.png differ diff --git a/app/img/placeholders/GroupAvatar1@2x.png b/app/img/placeholders/GroupAvatar1@2x.png new file mode 100755 index 00000000..99a1762b Binary files /dev/null and b/app/img/placeholders/GroupAvatar1@2x.png differ diff --git a/app/img/placeholders/GroupAvatar2@2x.png b/app/img/placeholders/GroupAvatar2@2x.png new file mode 100755 index 00000000..85619a50 Binary files /dev/null and b/app/img/placeholders/GroupAvatar2@2x.png differ diff --git a/app/img/placeholders/GroupAvatar3@2x.png b/app/img/placeholders/GroupAvatar3@2x.png new file mode 100755 index 00000000..f885d713 Binary files /dev/null and b/app/img/placeholders/GroupAvatar3@2x.png differ diff --git a/app/img/placeholders/GroupAvatar4@2x.png b/app/img/placeholders/GroupAvatar4@2x.png new file mode 100755 index 00000000..b8791555 Binary files /dev/null and b/app/img/placeholders/GroupAvatar4@2x.png differ diff --git a/app/img/placeholders/UserAvatar1@2x.png b/app/img/placeholders/UserAvatar1@2x.png new file mode 100755 index 00000000..ef56d3ae Binary files /dev/null and b/app/img/placeholders/UserAvatar1@2x.png differ diff --git a/app/img/placeholders/UserAvatar2@2x.png b/app/img/placeholders/UserAvatar2@2x.png new file mode 100755 index 00000000..ac3cb9ec Binary files /dev/null and b/app/img/placeholders/UserAvatar2@2x.png differ diff --git a/app/img/placeholders/UserAvatar3@2x.png b/app/img/placeholders/UserAvatar3@2x.png new file mode 100755 index 00000000..926ab975 Binary files /dev/null and b/app/img/placeholders/UserAvatar3@2x.png differ diff --git a/app/img/placeholders/UserAvatar4@2x.png b/app/img/placeholders/UserAvatar4@2x.png new file mode 100755 index 00000000..7e697fbe Binary files /dev/null and b/app/img/placeholders/UserAvatar4@2x.png differ diff --git a/app/img/placeholders/UserAvatar5@2x.png b/app/img/placeholders/UserAvatar5@2x.png new file mode 100755 index 00000000..de984d8b Binary files /dev/null and b/app/img/placeholders/UserAvatar5@2x.png differ diff --git a/app/img/placeholders/UserAvatar6@2x.png b/app/img/placeholders/UserAvatar6@2x.png new file mode 100755 index 00000000..9652cb98 Binary files /dev/null and b/app/img/placeholders/UserAvatar6@2x.png differ diff --git a/app/img/placeholders/UserAvatar7@2x.png b/app/img/placeholders/UserAvatar7@2x.png new file mode 100755 index 00000000..bf6e73f1 Binary files /dev/null and b/app/img/placeholders/UserAvatar7@2x.png differ diff --git a/app/img/placeholders/UserAvatar8@2x.png b/app/img/placeholders/UserAvatar8@2x.png new file mode 100755 index 00000000..614b75ef Binary files /dev/null and b/app/img/placeholders/UserAvatar8@2x.png differ diff --git a/app/index.html b/app/index.html new file mode 100644 index 00000000..1a806b4c --- /dev/null +++ b/app/index.html @@ -0,0 +1,45 @@ + + + + + + Webogram + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/js/app.js b/app/js/app.js new file mode 100644 index 00000000..828de512 --- /dev/null +++ b/app/js/app.js @@ -0,0 +1,55 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +'use strict'; + +// window._testMode = 1; + + +// Declare app level module which depends on filters, and services +angular.module('myApp', [ + 'ngRoute', + 'ngAnimate', + 'ngSanitize', + 'ui.bootstrap', + 'myApp.filters', + 'myApp.services', + 'mtproto.services', + 'myApp.directives', + 'myApp.controllers' +]). +config(['$locationProvider', '$routeProvider', '$compileProvider', function($locationProvider, $routeProvider, $compileProvider) { + + var icons = {}, reverseIcons = {}, i, j, hex, name, dataItem, + ranges = [[0x1f600, 0x1f637], [0x270a, 0x270c], [0x1f446, 0x1f450]]; + + for (j in ranges) { + for (i = ranges[j][0]; i <= ranges[j][1]; i++) { + hex = i.toString(16); + if (dataItem = Config.Emoji[hex]) { + name = dataItem[1][0]; + icons[':' + name + ':'] = hex + '.png'; + reverseIcons[name] = dataItem[0]; + } + } + } + + $.emojiarea.path = 'vendor/gemoji/images'; + $.emojiarea.icons = icons; + $.emojiarea.reverseIcons = reverseIcons; + + $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|file|blob|filesystem|chrome-extension):|data:image\//); + $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|file|mailto|blob|filesystem|chrome-extension):|data:image\//); + + + // $locationProvider.html5Mode(true); + $routeProvider.when('/', {templateUrl: 'partials/welcome.html', controller: 'AppWelcomeController'}); + $routeProvider.when('/login', {templateUrl: 'partials/login.html', controller: 'AppLoginController'}); + $routeProvider.when('/im', {templateUrl: 'partials/im.html', controller: 'AppIMController', reloadOnSearch: false}); + $routeProvider.otherwise({redirectTo: '/'}); + +}]); diff --git a/app/js/background.js b/app/js/background.js new file mode 100644 index 00000000..71f326cc --- /dev/null +++ b/app/js/background.js @@ -0,0 +1,18 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +chrome.app.runtime.onLaunched.addListener(function(launchData) { + chrome.app.window.create('../index.html', { + bounds: { + width: 1100, + height: 700 + }, + minWidth: 1100, + minHeight: 700, + frame: 'chrome' + }); +}); \ No newline at end of file diff --git a/app/js/controllers.js b/app/js/controllers.js new file mode 100644 index 00000000..15c8bcdd --- /dev/null +++ b/app/js/controllers.js @@ -0,0 +1,507 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +'use strict'; + +/* Controllers */ + +angular.module('myApp.controllers', []) + + .controller('AppWelcomeController', function($scope, $location, MtpApiManager) { + MtpApiManager.getUserID().then(function (id) { + if (id) { + $location.path('/im'); + } else { + $location.path('/login'); + } + }); + }) + + .controller('AppLoginController', function ($scope, $location, MtpApiManager) { + var dcID = 1; + + $scope.credentials = {}; + + function saveAuth (result) { + MtpApiManager.setUserAuth(dcID, { + expires: result.expires, + id: result.user.id + }); + + $location.path('/im'); + }; + + $scope.sendCode = function () { + MtpApiManager.invokeApi('auth.sendCode', { + phone_number: $scope.credentials.phone_number, + sms_type: 0, + api_id: 2496, + api_hash: '8da85b0d5bfe62527e5b244c209159c3' + }, {dcID: dcID}).then(function (sentCode) { + + $scope.credentials.phone_code_hash = sentCode.phone_code_hash; + $scope.credentials.phone_occupied = sentCode.phone_registered; + $scope.error = {}; + + }, function (error) { + dLog('sendCode', error); + if (error.code == 303) { + var newDcID = error.type.match(/^(PHONE_MIGRATE_|NETWORK_MIGRATE_)(\d+)/)[2]; + if (newDcID != dcID) { + dcID = newDcID; + $scope.sendCode(); + return; + } + } + switch (error.type) { + case 'PHONE_NUMBER_INVALID': + $scope.error = {field: 'phone'}; + break; + } + }); + } + + $scope.logIn = function (forceSignUp) { + var method = 'auth.signIn', params = { + phone_number: $scope.credentials.phone_number, + phone_code_hash: $scope.credentials.phone_code_hash, + phone_code: $scope.credentials.phone_code + }; + if (forceSignUp) { + method = 'auth.signUp'; + angular.extend(params, { + first_name: $scope.credentials.first_name, + last_name: $scope.credentials.last_name + }); + } + + MtpApiManager.invokeApi(method, params, {dcID: dcID}).then(saveAuth, function (error) { + if (error.code == 400 && error.type == 'PHONE_NUMBER_UNOCCUPIED') { + return $scope.logIn(true); + } else if (error.code == 400 && error.type == 'PHONE_NUMBER_UNOCCUPIED') { + return $scope.logIn(false); + } + + switch (error.type) { + case 'FIRSTNAME_INVALID': + $scope.error = {field: 'first_name'}; + break; + case 'LASTNAME_INVALID': + $scope.error = {field: 'last_name'}; + break; + case 'PHONE_CODE_INVALID': + $scope.error = {field: 'phone_code'}; + break; + } + }); + + }; + }) + + .controller('AppIMController', function ($scope, $location, $routeParams, MtpApiManager) { + + $scope.$on('$routeUpdate', updateCurDialog); + + $scope.isLoggedIn = true; + $scope.logOut = function () { + MtpApiManager.logOut().then(function () { + $location.path('/login'); + }); + } + + updateCurDialog(); + + + function updateCurDialog() { + $scope.curDialog = { + peer: $routeParams.p || false + }; + } + }) + + .controller('AppImDialogsController', function ($scope, $location, MtpApiManager, AppUsersManager, AppChatsManager, AppMessagesManager, AppPeersManager) { + + $scope.dialogs = []; + + var offset = 0, + hasMore = false, + limit = 20; + + + MtpApiManager.invokeApi('account.updateStatus', {offline: false}); + $scope.$on('dialogs_need_more', function () { + showMoreDialogs(); + }); + + $scope.$on('dialog_unread', function (e, dialog) { + angular.forEach($scope.dialogs, function(curDialog) { + if (curDialog.peerID == dialog.peerID) { + curDialog.unreadCount = dialog.unread_count; + } + }); + }); + + $scope.$on('dialogs_update', function (e, dialog) { + var pos = false; + angular.forEach($scope.dialogs, function(curDialog, curPos) { + if (curDialog.peerID == dialog.peerID) { + pos = curPos; + } + }); + + var wrappedDialog = AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count); + if (pos !== false) { + var prev = $scope.dialogs.splice(pos, 1); + wrappedDialog = angular.extend(prev[0], wrappedDialog); + offset++; + } + $scope.dialogs.unshift(wrappedDialog); + }); + + loadDialogs(); + + + + function loadDialogs (startLimit) { + offset = 0; + hasMore = false; + startLimit = startLimit || limit; + + AppMessagesManager.getDialogs(offset, startLimit).then(function (dialogsResult) { + offset += startLimit; + hasMore = offset < dialogsResult.count; + + $scope.dialogs = []; + angular.forEach(dialogsResult.dialogs, function (dialog) { + $scope.dialogs.push(AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count)); + }); + + $scope.$broadcast('ui_dialogs_change'); + }, function (error) { + if (error.code == 401) { + $location.path('/login'); + } + }); + } + + function showMoreDialogs () { + if (!hasMore || !offset) { + return; + } + + AppMessagesManager.getDialogs(offset, limit).then(function (dialogsResult) { + offset += limit; + hasMore = offset < dialogsResult.count; + + angular.forEach(dialogsResult.dialogs, function (dialog) { + $scope.dialogs.push(AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count)); + }); + + $scope.$broadcast('ui_dialogs_append'); + }); + } + + }) + + .controller('AppImHistoryController', function ($scope, $location, $timeout, MtpApiManager, AppUsersManager, AppChatsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager) { + + $scope.$watch('curDialog.peer', applyDialogSelect); + + ApiUpdatesManager.attach(); + + $scope.history = []; + $scope.typing = {}; + + var peerID, offset, hasMore, maxID, limit = 20; + + function applyDialogSelect (newPeer) { + newPeer = newPeer || $scope.curDialog.peer || ''; + + peerID = AppPeersManager.getPeerID(newPeer); + + $scope.curDialog.peerID = peerID; + $scope.curDialog.inputPeer = AppPeersManager.getInputPeer(newPeer); + + if (peerID) { + loadHistory(peerID); + } else { + showEmptyHistory(); + } + } + + function showMoreHistory () { + if (!hasMore || !offset) { + return; + } + + console.trace('load history'); + AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit).then(function (historyResult) { + offset += limit; + hasMore = offset < historyResult.count; + maxID = historyResult.history[historyResult.history.length - 1]; + + angular.forEach(historyResult.history, function (id) { + $scope.history.unshift(AppMessagesManager.wrapForHistory(id)); + }); + + $scope.$broadcast('ui_history_prepend'); + }, function () { + $scope.state = {error: true}; + }); + } + + function loadHistory () { + hasMore = false; + offset = 0; + maxID = 0; + + AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit).then(function (historyResult) { + offset += limit; + hasMore = offset < historyResult.count; + maxID = historyResult.history[historyResult.history.length - 1]; + + $scope.history = []; + angular.forEach(historyResult.history, function (id) { + $scope.history.push(AppMessagesManager.wrapForHistory(id)); + }); + $scope.history.reverse(); + + $scope.historyPeer = { + id: peerID, + data: AppPeersManager.getPeer(peerID), + photo: AppPeersManager.getPeerPhoto(peerID, 'User', 'Group') + }; + + $scope.typing = {}; + + MtpApiManager.getUserID().then(function (id) { + $scope.ownPhoto = AppUsersManager.getUserPhoto(id, 'User'); + }); + + $scope.state = {loaded: true}; + + $scope.$broadcast('ui_history_change'); + + AppMessagesManager.readHistory($scope.curDialog.inputPeer); + }, function () { + $scope.state = {error: true}; + }); + } + + function showEmptyHistory () { + $scope.state = {notSelected: true}; + $scope.history = []; + } + + + + var typingTimeouts = {}; + + $scope.$on('history_append', function (e, addedMessage) { + if (addedMessage.peerID == $scope.curDialog.peerID) { + dLog('append', addedMessage); + // console.trace(); + $scope.history.push(AppMessagesManager.wrapForHistory(addedMessage.messageID)); + $scope.typing = {}; + $scope.$broadcast('ui_history_append'); + offset++ + } + }); + + $scope.$on('apiUpdate', function (e, update) { + // dLog('on apiUpdate inline', update); + switch (update._) { + case 'updateUserTyping': + if (update.user_id == $scope.curDialog.peerID) { + $scope.typing = {user: AppUsersManager.getUser(update.user_id)}; + + $timeout.cancel(typingTimeouts[update.user_id]); + + typingTimeouts[update.user_id] = $timeout(function () { + $scope.typing = {}; + }, 6000); + } + break; + + case 'updateChatUserTyping': + if (-update.chat_id == $scope.curDialog.peerID) { + $scope.typing = {user: AppUsersManager.getUser(update.user_id)}; + + $timeout.cancel(typingTimeouts[update.user_id]); + + typingTimeouts[update.user_id] = $timeout(function () { + $scope.typing = {}; + }, 6000); + } + break; + } + }); + + $scope.$on('history_need_more', function () { + showMoreHistory(); + }); + + }) + + .controller('AppImPanelController', function($scope) { + $scope.$on('user_update', angular.noop); + }) + + .controller('AppImSendController', function ($scope, MtpApiManager, AppPeersManager, AppMessagesManager, ApiUpdatesManager, MtpApiFileManager) { + + $scope.$watch('curDialog.peer', resetDraft); + $scope.$on('user_update', angular.noop); + + $scope.draftMessage = {text: ''}; + + var lastTyping = false; + $scope.$watch('draftMessage.text', function (newVal) { + AppMessagesManager.readHistory($scope.curDialog.inputPeer); + + var now = +new Date(); + if (newVal === undefined || !newVal.length || now - lastTyping < 6000) { + return; + } + lastTyping = now; + + MtpApiManager.invokeApi('messages.setTyping', { + peer: $scope.curDialog.inputPeer, + typing: true + }); + }); + + $scope.sendMessage = sendMessage; + + $scope.$watch('draftMessage.files', onFilesSelected); + + function sendMessage (e) { + cancelEvent(e); + + var text = $scope.draftMessage.text; + + if ($scope.draftMessage.sending || !text.length) { + return false; + } + + text = text.replace(/:\s*(.+?)\s*:/g, function (all, name) { + var utfChar = $.emojiarea.reverseIcons[name]; + if (utfChar !== undefined) { + return utfChar; + } + return all; + }); + + $scope.draftMessage.sending = true; + + MtpApiManager.invokeApi('messages.sendMessage', { + peer: $scope.curDialog.inputPeer, + message: text, + random_id: $scope.draftMessage.randomID + }).then(function (result) { + + if (ApiUpdatesManager.saveSeq(result.seq)) { + + MtpApiManager.getUserID().then(function (fromID) { + ApiUpdatesManager.saveUpdate({ + _: 'updateNewMessage', + message: { + _: 'message', + id: result.id, + from_id: fromID, + to_id: AppPeersManager.getOutputPeer($scope.curDialog.peerID), + out: true, + unread: true, + date: result.date, + message: text, + media: {_: 'messageMediaEmpty'} + }, + pts: result.pts + }); + }); + + } + + $scope.$broadcast('ui_message_send'); + + resetDraft(); + }, function () { + delete $scope.draftMessage.sending; + }); + + return cancelEvent(e); + } + + + function resetDraft () { + $scope.draftMessage = { + randomID: [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)], + text: '' + }; + } + + function onFilesSelected (newVal) { + if (!angular.isArray(newVal) || !newVal.length) { + return; + } + + for (var i = 0; i < newVal.length; i++) { + (function (file, randomID) { + MtpApiFileManager.uploadFile(file).then(function (inputFile) { + var inputMedia; + if (file.type == 'image/jpeg') { + inputMedia = {_: 'inputMediaUploadedPhoto', file: inputFile}; + } else { + inputMedia = {_: 'inputMediaUploadedDocument', file: inputFile, file_name: file.name, mime_type: file.type}; + } + MtpApiManager.invokeApi('messages.sendMedia', { + peer: $scope.curDialog.inputPeer, + media: inputMedia, + random_id: randomID + }).then(function (result) { + + if (ApiUpdatesManager.saveSeq(result.seq)) { + ApiUpdatesManager.saveUpdate({ + _: 'updateNewMessage', + message: result.message, + pts: result.pts + }); + } + + $scope.$broadcast('ui_message_send'); + }); + }, function (error) { + dLog('upload error', error); + }) + + })(newVal[i], [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]); + } + } + + }) + + .controller('PhotoModalController', function ($scope, AppPhotosManager) { + $scope.photo = AppPhotosManager.wrapForFull($scope.photoID); + }) + + .controller('VideoModalController', function ($scope, AppVideoManager) { + $scope.video = AppVideoManager.wrapForFull($scope.videoID); + }) + + .controller('UserModalController', function ($scope, $location, AppUsersManager) { + $scope.user = AppUsersManager.wrapForFull($scope.userID); + $scope.goToHistory = function () { + $scope.$close(); + $location.url('/im?p=' + $scope.user.peerString); + }; + }) + + .controller('ChatModalController', function ($scope, AppUsersManager, AppChatsManager, fullChat) { + $scope.chatFull = AppChatsManager.wrapForFull($scope.chatID, fullChat); + }) + + + diff --git a/app/js/directives.js b/app/js/directives.js new file mode 100644 index 00000000..482a445e --- /dev/null +++ b/app/js/directives.js @@ -0,0 +1,512 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +'use strict'; + +/* Directives */ + + +angular.module('myApp.directives', ['myApp.filters']) + .directive('myDialog', function() { + return { + restrict: 'AE', + scope: true, + translude: false, + templateUrl: 'partials/dialog.html' + }; + }) + + .directive('myMessage', function() { + return { + restrict: 'AE', + scope: true, + translude: false, + templateUrl: 'partials/message.html' + }; + }) + + .directive('myDialogsList', function($window, $timeout) { + + return { + link: link + }; + + function link (scope, element, attrs) { + var dialogsWrap = $('.im_dialogs_wrap')[0], + scrollableWrap = $('.im_dialogs_scrollable_wrap')[0], + // dialogsSearch = $('im_dialogs_search')[0], + moreNotified = false; + + onContentLoaded(function () { + $(dialogsWrap).nanoScroller({preventPageScrolling: true, tabIndex: -1}); + }); + + var updateScroller = function () { + onContentLoaded(function () { + $(dialogsWrap).nanoScroller(); + }); + } + + scope.$on('ui_dialogs_prepend', updateScroller); + + + scope.$on('ui_dialogs_append', function () { + onContentLoaded(function () { + updateScroller(); + moreNotified = false; + }); + }); + + scope.$on('ui_dialogs_change', function () { + onContentLoaded(function () { + updateScroller(); + moreNotified = false; + }); + }); + + $(scrollableWrap).on('scroll', function (e) { + if (!moreNotified && scrollableWrap.scrollTop >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight - 300) { + scope.$emit('dialogs_need_more'); + moreNotified = true; + } + }); + + + function updateSizes () { + $(element).css({ + height: $($window).height() - 162 + }); + } + + $($window).on('resize', updateSizes); + + updateSizes(); + }; + + }) + + .directive('myHistory', function ($window, $timeout) { + + return { + link: link + }; + + function link (scope, element, attrs) { + var historyWrap = $('.im_history_wrap')[0], + scrollableWrap = $('.im_history_scrollable_wrap')[0], + scrollable = $('.im_history_scrollable')[0], + panelWrap = $('.im_history_panel_wrap', element)[0], + sendFormWrap = $('.im_send_form_wrap', element)[0], + moreNotified = false; + + onContentLoaded(function () { + $(historyWrap).nanoScroller({preventPageScrolling: true, scroll: 'bottom', tabIndex: -1}); + }); + + var updateScroller = function (delay) { + $timeout(function () { + $(historyWrap).nanoScroller(); + }, delay || 0); + } + + scope.$on('ui_history_append', function () { + var st = scrollableWrap.scrollTop; + $(scrollableWrap).addClass('im_history_to_bottom'); + if (atBottom) { + onContentLoaded(function () { + $(scrollableWrap).removeClass('im_history_to_bottom'); + updateSizes(); + $(historyWrap).nanoScroller({scrollBottom: 0}); + // scrollableWrap.scrollTop = st; + // $(scrollableWrap).animate({ + // scrollTop: scrollableWrap.scrollHeight - scrollableWrap.clientHeight + // }, 200); + updateScroller(); + }); + } + }); + + scope.$on('ui_history_change', function () { + $(scrollableWrap).addClass('im_history_to_bottom'); + $(scrollable).css({bottom: 0}); + onContentLoaded(function () { + $(scrollableWrap).removeClass('im_history_to_bottom'); + $(scrollable).css({bottom: ''}); + updateSizes(); + $(historyWrap).nanoScroller(); + $(historyWrap).nanoScroller({scrollBottom: 0}); + updateScroller(100); + moreNotified = false; + }); + }); + + + scope.$on('ui_history_prepend', function () { + var sh = scrollableWrap.scrollHeight, + st = scrollableWrap.scrollTop, + ch = scrollableWrap.clientHeight; + + $(scrollableWrap).addClass('im_history_to_bottom'); + $(scrollable).css({bottom: -(sh - st - ch)}); + + onContentLoaded(function () { + $(scrollableWrap).removeClass('im_history_to_bottom'); + $(scrollable).css({bottom: ''}); + $(historyWrap).nanoScroller(); + $(historyWrap).nanoScroller({scrollTop: st + scrollableWrap.scrollHeight - sh}); + + // updateScroller(); + updateScroller(50); + moreNotified = false; + }); + }); + + var atBottom = true; + $(scrollableWrap).on('scroll', function (e) { + atBottom = scrollableWrap.scrollTop >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight; + + if (!moreNotified && scrollableWrap.scrollTop <= 300) { + moreNotified = true; + scope.$emit('history_need_more'); + } + }); + + function updateSizes () { + $(historyWrap).css({ + height: $($window).height() - panelWrap.offsetHeight - sendFormWrap.offsetHeight - 90 + }); + if (atBottom) { + onContentLoaded(function () { + $(historyWrap).nanoScroller({scroll: 'bottom'}); + }); + } + updateScroller(100); + } + + $($window).on('resize', updateSizes); + + onContentLoaded(updateSizes); + } + + }) + + .directive('mySendForm', function ($timeout) { + + return { + link: link, + scope: { + draftMessage: '=' + } + }; + + function link (scope, element, attrs) { + var messageField = $('textarea', element)[0], + fileSelect = $('input', element)[0], + dropbox = $('.im_send_dropbox_wrap', element)[0], + emojiButton = $('.im_emoji_btn', element)[0], + editorElement = messageField, + dragStarted, dragTimeout, + emojiArea = $(messageField).emojiarea({button: emojiButton}), + emojiMenu = $('.emoji-menu')[0], + richTextarea = $('.emoji-wysiwyg-editor', element)[0]; + + if (richTextarea) { + editorElement = richTextarea; + $(richTextarea).addClass('form-control'); + $(richTextarea).attr('placeholder', $(messageField).attr('placeholder')); + } + + // $(emojiMenu.firstChild).addClass('nano').nanoScroller({preventPageScrolling: true, tabIndex: -1}); + + + $(fileSelect).on('change', function () { + scope.$apply(function () { + scope.draftMessage.files = Array.prototype.slice.call(fileSelect.files); + }); + }); + + var sendOnEnter = true; + $(editorElement).on('keydown', function (e) { + if (e.keyCode != 13) { + return; + } + var submit = false; + if (sendOnEnter && !e.shiftKey) { + submit = true; + } else if (!sendOnEnter && (e.ctrlKey || e.metaKey)) { + submit = true; + } + + if (submit) { + $(element).trigger('submit'); + dLog('after submit'); + return cancelEvent(e); + } + }); + + if (richTextarea) { + scope.$watch('draftMessage.text', function (newVal) { + if (!newVal.length && !messageField.value.length) { + $timeout(function () { + $(richTextarea).html(''); + }, 0); + } + }); + } + + + $('body').on('dragenter dragleave dragover drop', onDragDropEvent); + + scope.$on('ui_history_change', focusField); + scope.$on('ui_message_send', focusField); + + scope.$on('$destroy', function cleanup() { + $('body').off('dragenter dragleave dragover drop', onDragDropEvent); + }); + + focusField(); + + function focusField () { + onContentLoaded(function () { + $(editorElement).focus(); + }); + } + + function onDragDropEvent(e) { + var dragStateChanged = false; + if (!dragStarted || dragStarted == 1) { + dragStarted = checkDragEvent(e) ? 2 : 1; + dragStateChanged = true; + } + if (dragStarted == 2) { + if (dragTimeout) { + setTimeout(function () { + clearTimeout(dragTimeout); + dragTimeout = false; + }, 0); + } + + if (e.type == 'dragenter' || e.type == 'dragover') { + if (dragStateChanged) { + $(dropbox) + .css({height: $(editorElement).height() + 12, width: $(editorElement).width() + 12}) + .show(); + } + } else { + if (e.type == 'drop') { + scope.$apply(function () { + scope.draftMessage.files = Array.prototype.slice.call(e.originalEvent.dataTransfer.files); + }); + } + dragTimeout = setTimeout(function () { + $(dropbox).hide(); + dragStarted = false; + dragTimeout = false; + }, 300); + } + } + + return cancelEvent(e); + }; + } + + }) + + .directive('myLoadThumb', function(MtpApiFileManager) { + + return { + link: link, + scope: { + thumb: '=' + } + }; + + function link (scope, element, attrs) { + + scope.$watch('thumb.location', function (newVal) { + if (!scope.thumb) dLog(222, scope); + if (!scope.thumb.location) { + element.attr('src', scope.thumb.placeholder || ''); + return; + } + + MtpApiFileManager.downloadSmallFile(scope.thumb.location, scope.thumb.size).then(function (url) { + element.attr('src', url); + }, function (e) { + dLog('Download image failed', e, scope.thumb.location); + element.attr('src', scope.thumb.placeholder || ''); + }); + }) + + } + + }) + + .directive('myLoadFullPhoto', function(MtpApiFileManager) { + + return { + link: link, + transclude: true, + template: + '
\ +
\ +
\ +
\ +
\ + {{progress.percent}}% Complete (success)\ +
\ +
\ +
\ +
\ +
\ + \ + \ + \ +
\ +
', + scope: { + fullPhoto: '=', + thumbLocation: '=' + } + }; + + function link (scope, element, attrs) { + var imgElement = $('img', element), + fullLoaded = false; + + + if (!scope.fullPhoto.location) { + imgElement.attr('src', scope.fullPhoto.placeholder || ''); + return; + } + + MtpApiFileManager.getCachedFile(scope.thumbLocation).then(function (url) { + if (!fullLoaded) { + imgElement + .attr('src', url) + .addClass('thumb_blurred') + .addClass('thumb_blur_animation'); + } + }); + + var apiPromise; + if (scope.fullPhoto.size) { + var inputLocation = { + _: 'inputFileLocation', + volume_id: scope.fullPhoto.location.volume_id, + local_id: scope.fullPhoto.location.local_id, + secret: scope.fullPhoto.location.secret + }; + apiPromise = MtpApiFileManager.downloadFile(scope.fullPhoto.location.dc_id, inputLocation, scope.fullPhoto.size); + } else { + apiPromise = MtpApiFileManager.downloadSmallFile(scope.fullPhoto.location); + } + + scope.progress = {enabled: true, percent: 1}; + + apiPromise.then(function (url) { + fullLoaded = true; + scope.progress.enabled = false; + imgElement + .attr('src', url) + .removeClass('thumb_blurred'); + + }, function (e) { + dLog('Download image failed', e, scope.fullPhoto.location); + scope.progress.enabled = false; + imgElement + .attr('src', scope.fullPhoto.placeholder || '') + .removeClass('thumb_blurred'); + + }, function (progress) { + scope.progress.percent = Math.max(1, Math.floor(100 * progress.done / progress.total)); + }); + } + + }) + + + .directive('myLoadVideo', function($sce, MtpApiFileManager) { + + return { + link: link, + transclude: true, + template: + '
\ +
\ +
\ +
\ +
\ + {{progress.percent}}% Complete (success)\ +
\ +
\ +
\ +
\ +
\ + \ +
\ +
\ + \ +
\ +
', + scope: { + video: '=' + } + }; + + function link (scope, element, attrs) { + + scope.progress = {enabled: true, percent: 1}; + scope.player = {}; + + var inputLocation = { + _: 'inputVideoFileLocation', + id: scope.video.id, + access_hash: scope.video.access_hash + }; + + MtpApiFileManager.downloadFile(scope.video.dc_id, inputLocation, scope.video.size).then(function (url) { + scope.progress.enabled = false; + // scope.progress = {enabled: true, percent: 50}; + scope.player.src = $sce.trustAsResourceUrl(url); + }, function (e) { + dLog('Download image failed', e, scope.fullPhoto.location); + scope.progress.enabled = false; + scope.player.src = ''; + }, function (progress) { + scope.progress.percent = Math.max(1, Math.floor(100 * progress.done / progress.total)); + }); + } + + }) + + .directive('myMapPoint', function(ExternalResourcesManager) { + + return { + link: link, + scope: { + point: '=' + } + }; + + function link (scope, element, attrs) { + + var apiKey = 'AIzaSyC32ij28dCa0YzEV_HqbWfIwTZQql-RNS0'; + + var src = 'https://maps.googleapis.com/maps/api/staticmap?sensor=false¢er=' + scope.point['lat'] + ',' + scope.point['long'] + '&zoom=13&size=200x100&scale=2&key=' + apiKey; + + ExternalResourcesManager.downloadImage(src).then(function (url) { + element.append(''); + }); + + element.attr('href','https://maps.google.com/?q=' + scope.point['lat'] + ',' + scope.point['long']); + element.attr('target','_blank'); + } + + }) diff --git a/app/js/filters.js b/app/js/filters.js new file mode 100644 index 00000000..a2914d42 --- /dev/null +++ b/app/js/filters.js @@ -0,0 +1,126 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +'use strict'; + +/* Filters */ + +angular.module('myApp.filters', []) + + .filter('userName', [function() { + return function (user) { + if (!user || !user.first_name && !user.last_name) { + return 'DELETED'; + } + return user.first_name + ' ' + user.last_name; + } + }]) + + .filter('userFirstName', [function() { + return function (user) { + if (!user || !user.first_name && !user.last_name) { + return 'DELETED'; + } + return user.first_name || user.last_name; + } + }]) + + .filter('userStatus', ['$filter', function($filter) { + return function (user) { + if (!user || !user.status || user.status._ == 'userStatusEmpty') { + return 'offline'; + } + if (user.status._ == 'userStatusOnline') { + return 'online'; + } + + return 'last seen ' + $filter('relativeTime')(user.status.was_online); + } + }]) + + .filter('chatTitle', [function() { + return function (chat) { + if (!chat || !chat.title) { + return 'DELETED'; + } + return chat.title; + } + }]) + + .filter('dateOrTime', ['$filter', function($filter) { + return function (timestamp) { + var ticks = timestamp * 1000, + diff = Math.abs(+new Date() - ticks), + format = 'HH:mm'; + + if (diff > 518400000) { // 6 days + format = 'shortDate'; + } + else if (diff > 43200000) { // 12 hours + format = 'EEE'; + } + return $filter('date')(ticks, format); + } + }]) + + .filter('duration', [function() { + return function (duration) { + var secs = duration % 60, + mins = Math.floor((duration - secs) / 60.0); + + if (secs < 10) { + secs = '0' + secs; + } + + return mins + ':' + secs; + } + }]) + + .filter('phoneNumber', [function() { + return function (phoneRaw) { + if (phoneRaw.charAt(0) == '7') { + return '+' + phoneRaw.charAt(0) + ' (' + phoneRaw.substr(1, 3) + ') ' + phoneRaw.substr(4, 3) + '-' + phoneRaw.substr(7, 2) + '-' + phoneRaw.substr(9, 2); + } + return '+' + phoneRaw; + } + }]) + + .filter('formatSize', [function () { + return function (size) { + return Math.round(size / 1024) + 'Kb'; + } + }]) + + .filter('nl2br', [function () { + return function (text) { + return text.replace(/\n/g, '
'); + } + }]) + + .filter('richText', ['$filter', function ($filter) { + return function (text) { + return $filter('linky')(text, '_blank').replace(/\n| /g, '
'); + } + }]) + + .filter('relativeTime', ['$filter', function($filter) { + return function (timestamp) { + var ticks = timestamp * 1000, + diff = Math.abs(+new Date() - ticks); + + if (diff < 60000) { + return 'just now'; + } + if (diff < 3000000) { + return Math.ceil(diff / 60000) + ' minutes ago'; + } + if (diff < 10000000) { + return Math.ceil(diff / 3600000) + ' hours ago'; + } + return $filter('dateOrTime')(timestamp); + } + }]) \ No newline at end of file diff --git a/app/js/lib/aes_worker.js b/app/js/lib/aes_worker.js new file mode 100644 index 00000000..fe1ff83b --- /dev/null +++ b/app/js/lib/aes_worker.js @@ -0,0 +1,21 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +importScripts('mtproto.js', '../../vendor/jsbn/jsbn_combined.js', '../../vendor/cryptoJS/crypto.js'); + +onmessage = function (e) { + // console.log('AES worker in', e.data); + var taskID = e.data.taskID, + result; + + if (e.data.task == 'encrypt') { + result = aesEncrypt(e.data.bytes, e.data.keyBytes, e.data.ivBytes); + } else { + result = aesDecrypt(e.data.encryptedBytes, e.data.keyBytes, e.data.ivBytes); + } + postMessage({taskID: taskID, result: result}); +} \ No newline at end of file diff --git a/app/js/lib/config.js b/app/js/lib/config.js new file mode 100644 index 00000000..7f7ef7ad --- /dev/null +++ b/app/js/lib/config.js @@ -0,0 +1,14 @@ +Config = window.Config || {}; +Config.Schema = Config.Schema || {}; + + +Config.Schema.MTProto = {"constructors":[{"id":"481674261","predicate":"vector","params":[],"type":"Vector t"},{"id":"85337187","predicate":"resPQ","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"pq","type":"bytes"},{"name":"server_public_key_fingerprints","type":"Vector"}],"type":"ResPQ"},{"id":"-2083955988","predicate":"p_q_inner_data","params":[{"name":"pq","type":"bytes"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce","type":"int256"}],"type":"P_Q_inner_data"},{"id":"2043348061","predicate":"server_DH_params_fail","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash","type":"int128"}],"type":"Server_DH_Params"},{"id":"-790100132","predicate":"server_DH_params_ok","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"encrypted_answer","type":"bytes"}],"type":"Server_DH_Params"},{"id":"-1249309254","predicate":"server_DH_inner_data","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"g","type":"int"},{"name":"dh_prime","type":"bytes"},{"name":"g_a","type":"bytes"},{"name":"server_time","type":"int"}],"type":"Server_DH_inner_data"},{"id":"1715713620","predicate":"client_DH_inner_data","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"retry_id","type":"long"},{"name":"g_b","type":"bytes"}],"type":"Client_DH_Inner_Data"},{"id":"1003222836","predicate":"dh_gen_ok","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash1","type":"int128"}],"type":"Set_client_DH_params_answer"},{"id":"1188831161","predicate":"dh_gen_retry","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash2","type":"int128"}],"type":"Set_client_DH_params_answer"},{"id":"-1499615742","predicate":"dh_gen_fail","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash3","type":"int128"}],"type":"Set_client_DH_params_answer"},{"id":"-212046591","predicate":"rpc_result","params":[{"name":"req_msg_id","type":"long"},{"name":"result","type":"Object"}],"type":"RpcResult"},{"id":"558156313","predicate":"rpc_error","params":[{"name":"error_code","type":"int"},{"name":"error_message","type":"string"}],"type":"RpcError"},{"id":"1579864942","predicate":"rpc_answer_unknown","params":[],"type":"RpcDropAnswer"},{"id":"-847714938","predicate":"rpc_answer_dropped_running","params":[],"type":"RpcDropAnswer"},{"id":"-1539647305","predicate":"rpc_answer_dropped","params":[{"name":"msg_id","type":"long"},{"name":"seq_no","type":"int"},{"name":"bytes","type":"int"}],"type":"RpcDropAnswer"},{"id":"155834844","predicate":"future_salt","params":[{"name":"valid_since","type":"int"},{"name":"valid_until","type":"int"},{"name":"salt","type":"long"}],"type":"FutureSalt"},{"id":"-1370486635","predicate":"future_salts","params":[{"name":"req_msg_id","type":"long"},{"name":"now","type":"int"},{"name":"salts","type":"vector"}],"type":"FutureSalts"},{"id":"880243653","predicate":"pong","params":[{"name":"msg_id","type":"long"},{"name":"ping_id","type":"long"}],"type":"Pong"},{"id":"-501201412","predicate":"destroy_session_ok","params":[{"name":"session_id","type":"long"}],"type":"DestroySessionRes"},{"id":"1658015945","predicate":"destroy_session_none","params":[{"name":"session_id","type":"long"}],"type":"DestroySessionRes"},{"id":"-1631450872","predicate":"new_session_created","params":[{"name":"first_msg_id","type":"long"},{"name":"unique_id","type":"long"},{"name":"server_salt","type":"long"}],"type":"NewSession"},{"id":"1945237724","predicate":"msg_container","params":[{"name":"messages","type":"vector<%Message>"}],"type":"MessageContainer"},{"id":"1538843921","predicate":"message","params":[{"name":"msg_id","type":"long"},{"name":"seqno","type":"int"},{"name":"bytes","type":"int"},{"name":"body","type":"Object"}],"type":"Message"},{"id":"-530561358","predicate":"msg_copy","params":[{"name":"orig_message","type":"Message"}],"type":"MessageCopy"},{"id":"812830625","predicate":"gzip_packed","params":[{"name":"packed_data","type":"bytes"}],"type":"Object"},{"id":"1658238041","predicate":"msgs_ack","params":[{"name":"msg_ids","type":"Vector"}],"type":"MsgsAck"},{"id":"-1477445615","predicate":"bad_msg_notification","params":[{"name":"bad_msg_id","type":"long"},{"name":"bad_msg_seqno","type":"int"},{"name":"error_code","type":"int"}],"type":"BadMsgNotification"},{"id":"-307542917","predicate":"bad_server_salt","params":[{"name":"bad_msg_id","type":"long"},{"name":"bad_msg_seqno","type":"int"},{"name":"error_code","type":"int"},{"name":"new_server_salt","type":"long"}],"type":"BadMsgNotification"},{"id":"2105940488","predicate":"msg_resend_req","params":[{"name":"msg_ids","type":"Vector"}],"type":"MsgResendReq"},{"id":"-630588590","predicate":"msgs_state_req","params":[{"name":"msg_ids","type":"Vector"}],"type":"MsgsStateReq"},{"id":"81704317","predicate":"msgs_state_info","params":[{"name":"req_msg_id","type":"long"},{"name":"info","type":"bytes"}],"type":"MsgsStateInfo"},{"id":"-1933520591","predicate":"msgs_all_info","params":[{"name":"msg_ids","type":"Vector"},{"name":"info","type":"bytes"}],"type":"MsgsAllInfo"},{"id":"661470918","predicate":"msg_detailed_info","params":[{"name":"msg_id","type":"long"},{"name":"answer_msg_id","type":"long"},{"name":"bytes","type":"int"},{"name":"status","type":"int"}],"type":"MsgDetailedInfo"},{"id":"-2137147681","predicate":"msg_new_detailed_info","params":[{"name":"answer_msg_id","type":"long"},{"name":"bytes","type":"int"},{"name":"status","type":"int"}],"type":"MsgDetailedInfo"}],"methods":[{"id":"1615239032","method":"req_pq","params":[{"name":"nonce","type":"int128"}],"type":"ResPQ"},{"id":"-686627650","method":"req_DH_params","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"public_key_fingerprint","type":"long"},{"name":"encrypted_data","type":"bytes"}],"type":"Server_DH_Params"},{"id":"-184262881","method":"set_client_DH_params","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"encrypted_data","type":"bytes"}],"type":"Set_client_DH_params_answer"},{"id":"1491380032","method":"rpc_drop_answer","params":[{"name":"req_msg_id","type":"long"}],"type":"RpcDropAnswer"},{"id":"-1188971260","method":"get_future_salts","params":[{"name":"num","type":"int"}],"type":"FutureSalts"},{"id":"2059302892","method":"ping","params":[{"name":"ping_id","type":"long"}],"type":"Pong"},{"id":"-213746804","method":"ping_delay_disconnect","params":[{"name":"ping_id","type":"long"},{"name":"disconnect_delay","type":"int"}],"type":"Pong"},{"id":"-414113498","method":"destroy_session","params":[{"name":"session_id","type":"long"}],"type":"DestroySessionRes"},{"id":"-1835453025","method":"http_wait","params":[{"name":"max_delay","type":"int"},{"name":"wait_after","type":"int"},{"name":"max_wait","type":"int"}],"type":"HttpWait"}]}; + + + + +Config.Schema.API = {"constructors":[{"id":"-1132882121","predicate":"boolFalse","params":[],"type":"Bool"},{"id":"-1720552011","predicate":"boolTrue","params":[],"type":"Bool"},{"id":"481674261","predicate":"vector","params":[],"type":"Vector t"},{"id":"-994444869","predicate":"error","params":[{"name":"code","type":"int"},{"name":"text","type":"string"}],"type":"Error"},{"id":"1450380236","predicate":"null","params":[],"type":"Null"},{"id":"2134579434","predicate":"inputPeerEmpty","params":[],"type":"InputPeer"},{"id":"2107670217","predicate":"inputPeerSelf","params":[],"type":"InputPeer"},{"id":"270785512","predicate":"inputPeerContact","params":[{"name":"user_id","type":"int"}],"type":"InputPeer"},{"id":"-1690012891","predicate":"inputPeerForeign","params":[{"name":"user_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputPeer"},{"id":"396093539","predicate":"inputPeerChat","params":[{"name":"chat_id","type":"int"}],"type":"InputPeer"},{"id":"-1182234929","predicate":"inputUserEmpty","params":[],"type":"InputUser"},{"id":"-138301121","predicate":"inputUserSelf","params":[],"type":"InputUser"},{"id":"-2031530139","predicate":"inputUserContact","params":[{"name":"user_id","type":"int"}],"type":"InputUser"},{"id":"1700689151","predicate":"inputUserForeign","params":[{"name":"user_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputUser"},{"id":"-208488460","predicate":"inputPhoneContact","params":[{"name":"client_id","type":"long"},{"name":"phone","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"InputContact"},{"id":"-181407105","predicate":"inputFile","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"name","type":"string"},{"name":"md5_checksum","type":"string"}],"type":"InputFile"},{"id":"-1771768449","predicate":"inputMediaEmpty","params":[],"type":"InputMedia"},{"id":"767900285","predicate":"inputMediaUploadedPhoto","params":[{"name":"file","type":"InputFile"}],"type":"InputMedia"},{"id":"-1893027092","predicate":"inputMediaPhoto","params":[{"name":"id","type":"InputPhoto"}],"type":"InputMedia"},{"id":"-104578748","predicate":"inputMediaGeoPoint","params":[{"name":"geo_point","type":"InputGeoPoint"}],"type":"InputMedia"},{"id":"-1494984313","predicate":"inputMediaContact","params":[{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"InputMedia"},{"id":"1212668202","predicate":"inputMediaUploadedVideo","params":[{"name":"file","type":"InputFile"},{"name":"duration","type":"int"},{"name":"w","type":"int"},{"name":"h","type":"int"}],"type":"InputMedia"},{"id":"-433544891","predicate":"inputMediaUploadedThumbVideo","params":[{"name":"file","type":"InputFile"},{"name":"thumb","type":"InputFile"},{"name":"duration","type":"int"},{"name":"w","type":"int"},{"name":"h","type":"int"}],"type":"InputMedia"},{"id":"2130852582","predicate":"inputMediaVideo","params":[{"name":"id","type":"InputVideo"}],"type":"InputMedia"},{"id":"480546647","predicate":"inputChatPhotoEmpty","params":[],"type":"InputChatPhoto"},{"id":"-1809496270","predicate":"inputChatUploadedPhoto","params":[{"name":"file","type":"InputFile"},{"name":"crop","type":"InputPhotoCrop"}],"type":"InputChatPhoto"},{"id":"-1293828344","predicate":"inputChatPhoto","params":[{"name":"id","type":"InputPhoto"},{"name":"crop","type":"InputPhotoCrop"}],"type":"InputChatPhoto"},{"id":"-457104426","predicate":"inputGeoPointEmpty","params":[],"type":"InputGeoPoint"},{"id":"-206066487","predicate":"inputGeoPoint","params":[{"name":"lat","type":"double"},{"name":"long","type":"double"}],"type":"InputGeoPoint"},{"id":"483901197","predicate":"inputPhotoEmpty","params":[],"type":"InputPhoto"},{"id":"-74070332","predicate":"inputPhoto","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputPhoto"},{"id":"1426648181","predicate":"inputVideoEmpty","params":[],"type":"InputVideo"},{"id":"-296249774","predicate":"inputVideo","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputVideo"},{"id":"342061462","predicate":"inputFileLocation","params":[{"name":"volume_id","type":"long"},{"name":"local_id","type":"int"},{"name":"secret","type":"long"}],"type":"InputFileLocation"},{"id":"1023632620","predicate":"inputVideoFileLocation","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputFileLocation"},{"id":"-1377390588","predicate":"inputPhotoCropAuto","params":[],"type":"InputPhotoCrop"},{"id":"-644787419","predicate":"inputPhotoCrop","params":[{"name":"crop_left","type":"double"},{"name":"crop_top","type":"double"},{"name":"crop_width","type":"double"}],"type":"InputPhotoCrop"},{"id":"1996904104","predicate":"inputAppEvent","params":[{"name":"time","type":"double"},{"name":"type","type":"string"},{"name":"peer","type":"long"},{"name":"data","type":"string"}],"type":"InputAppEvent"},{"id":"-1649296275","predicate":"peerUser","params":[{"name":"user_id","type":"int"}],"type":"Peer"},{"id":"-1160714821","predicate":"peerChat","params":[{"name":"chat_id","type":"int"}],"type":"Peer"},{"id":"-1432995067","predicate":"storage.fileUnknown","params":[],"type":"storage.FileType"},{"id":"8322574","predicate":"storage.fileJpeg","params":[],"type":"storage.FileType"},{"id":"-891180321","predicate":"storage.fileGif","params":[],"type":"storage.FileType"},{"id":"172975040","predicate":"storage.filePng","params":[],"type":"storage.FileType"},{"id":"1384777335","predicate":"storage.fileMp3","params":[],"type":"storage.FileType"},{"id":"1258941372","predicate":"storage.fileMov","params":[],"type":"storage.FileType"},{"id":"1086091090","predicate":"storage.filePartial","params":[],"type":"storage.FileType"},{"id":"-1278304028","predicate":"storage.fileMp4","params":[],"type":"storage.FileType"},{"id":"276907596","predicate":"storage.fileWebp","params":[],"type":"storage.FileType"},{"id":"2086234950","predicate":"fileLocationUnavailable","params":[{"name":"volume_id","type":"long"},{"name":"local_id","type":"int"},{"name":"secret","type":"long"}],"type":"FileLocation"},{"id":"1406570614","predicate":"fileLocation","params":[{"name":"dc_id","type":"int"},{"name":"volume_id","type":"long"},{"name":"local_id","type":"int"},{"name":"secret","type":"long"}],"type":"FileLocation"},{"id":"537022650","predicate":"userEmpty","params":[{"name":"id","type":"int"}],"type":"User"},{"id":"1912944108","predicate":"userSelf","params":[{"name":"id","type":"int"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"phone","type":"string"},{"name":"photo","type":"UserProfilePhoto"},{"name":"status","type":"UserStatus"},{"name":"inactive","type":"Bool"}],"type":"User"},{"id":"-218397927","predicate":"userContact","params":[{"name":"id","type":"int"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"access_hash","type":"long"},{"name":"phone","type":"string"},{"name":"photo","type":"UserProfilePhoto"},{"name":"status","type":"UserStatus"}],"type":"User"},{"id":"585682608","predicate":"userRequest","params":[{"name":"id","type":"int"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"access_hash","type":"long"},{"name":"phone","type":"string"},{"name":"photo","type":"UserProfilePhoto"},{"name":"status","type":"UserStatus"}],"type":"User"},{"id":"1377093789","predicate":"userForeign","params":[{"name":"id","type":"int"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"access_hash","type":"long"},{"name":"photo","type":"UserProfilePhoto"},{"name":"status","type":"UserStatus"}],"type":"User"},{"id":"-1298475060","predicate":"userDeleted","params":[{"name":"id","type":"int"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"User"},{"id":"1326562017","predicate":"userProfilePhotoEmpty","params":[],"type":"UserProfilePhoto"},{"id":"-715532088","predicate":"userProfilePhoto","params":[{"name":"photo_id","type":"long"},{"name":"photo_small","type":"FileLocation"},{"name":"photo_big","type":"FileLocation"}],"type":"UserProfilePhoto"},{"id":"164646985","predicate":"userStatusEmpty","params":[],"type":"UserStatus"},{"id":"-306628279","predicate":"userStatusOnline","params":[{"name":"expires","type":"int"}],"type":"UserStatus"},{"id":"9203775","predicate":"userStatusOffline","params":[{"name":"was_online","type":"int"}],"type":"UserStatus"},{"id":"-1683826688","predicate":"chatEmpty","params":[{"name":"id","type":"int"}],"type":"Chat"},{"id":"1855757255","predicate":"chat","params":[{"name":"id","type":"int"},{"name":"title","type":"string"},{"name":"photo","type":"ChatPhoto"},{"name":"participants_count","type":"int"},{"name":"date","type":"int"},{"name":"left","type":"Bool"},{"name":"version","type":"int"}],"type":"Chat"},{"id":"-83047359","predicate":"chatForbidden","params":[{"name":"id","type":"int"},{"name":"title","type":"string"},{"name":"date","type":"int"}],"type":"Chat"},{"id":"1661886910","predicate":"chatFull","params":[{"name":"id","type":"int"},{"name":"participants","type":"ChatParticipants"},{"name":"chat_photo","type":"Photo"},{"name":"notify_settings","type":"PeerNotifySettings"}],"type":"ChatFull"},{"id":"-925415106","predicate":"chatParticipant","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChatParticipant"},{"id":"265468810","predicate":"chatParticipantsForbidden","params":[{"name":"chat_id","type":"int"}],"type":"ChatParticipants"},{"id":"2017571861","predicate":"chatParticipants","params":[{"name":"chat_id","type":"int"},{"name":"admin_id","type":"int"},{"name":"participants","type":"Vector"},{"name":"version","type":"int"}],"type":"ChatParticipants"},{"id":"935395612","predicate":"chatPhotoEmpty","params":[],"type":"ChatPhoto"},{"id":"1632839530","predicate":"chatPhoto","params":[{"name":"photo_small","type":"FileLocation"},{"name":"photo_big","type":"FileLocation"}],"type":"ChatPhoto"},{"id":"-2082087340","predicate":"messageEmpty","params":[{"name":"id","type":"int"}],"type":"Message"},{"id":"585853626","predicate":"message","params":[{"name":"id","type":"int"},{"name":"from_id","type":"int"},{"name":"to_id","type":"Peer"},{"name":"out","type":"Bool"},{"name":"unread","type":"Bool"},{"name":"date","type":"int"},{"name":"message","type":"string"},{"name":"media","type":"MessageMedia"}],"type":"Message"},{"id":"99903492","predicate":"messageForwarded","params":[{"name":"id","type":"int"},{"name":"fwd_from_id","type":"int"},{"name":"fwd_date","type":"int"},{"name":"from_id","type":"int"},{"name":"to_id","type":"Peer"},{"name":"out","type":"Bool"},{"name":"unread","type":"Bool"},{"name":"date","type":"int"},{"name":"message","type":"string"},{"name":"media","type":"MessageMedia"}],"type":"Message"},{"id":"-1618124613","predicate":"messageService","params":[{"name":"id","type":"int"},{"name":"from_id","type":"int"},{"name":"to_id","type":"Peer"},{"name":"out","type":"Bool"},{"name":"unread","type":"Bool"},{"name":"date","type":"int"},{"name":"action","type":"MessageAction"}],"type":"Message"},{"id":"1038967584","predicate":"messageMediaEmpty","params":[],"type":"MessageMedia"},{"id":"-926655958","predicate":"messageMediaPhoto","params":[{"name":"photo","type":"Photo"}],"type":"MessageMedia"},{"id":"-1563278704","predicate":"messageMediaVideo","params":[{"name":"video","type":"Video"}],"type":"MessageMedia"},{"id":"1457575028","predicate":"messageMediaGeo","params":[{"name":"geo","type":"GeoPoint"}],"type":"MessageMedia"},{"id":"1585262393","predicate":"messageMediaContact","params":[{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"user_id","type":"int"}],"type":"MessageMedia"},{"id":"694364726","predicate":"messageMediaUnsupported","params":[{"name":"bytes","type":"bytes"}],"type":"MessageMedia"},{"id":"-1230047312","predicate":"messageActionEmpty","params":[],"type":"MessageAction"},{"id":"-1503425638","predicate":"messageActionChatCreate","params":[{"name":"title","type":"string"},{"name":"users","type":"Vector"}],"type":"MessageAction"},{"id":"-1247687078","predicate":"messageActionChatEditTitle","params":[{"name":"title","type":"string"}],"type":"MessageAction"},{"id":"2144015272","predicate":"messageActionChatEditPhoto","params":[{"name":"photo","type":"Photo"}],"type":"MessageAction"},{"id":"-1780220945","predicate":"messageActionChatDeletePhoto","params":[],"type":"MessageAction"},{"id":"1581055051","predicate":"messageActionChatAddUser","params":[{"name":"user_id","type":"int"}],"type":"MessageAction"},{"id":"-1297179892","predicate":"messageActionChatDeleteUser","params":[{"name":"user_id","type":"int"}],"type":"MessageAction"},{"id":"558533855","predicate":"dialog","params":[{"name":"peer","type":"Peer"},{"name":"top_message","type":"int"},{"name":"unread_count","type":"int"}],"type":"Dialog"},{"id":"590459437","predicate":"photoEmpty","params":[{"name":"id","type":"long"}],"type":"Photo"},{"id":"582313809","predicate":"photo","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"user_id","type":"int"},{"name":"date","type":"int"},{"name":"caption","type":"string"},{"name":"geo","type":"GeoPoint"},{"name":"sizes","type":"Vector"}],"type":"Photo"},{"id":"236446268","predicate":"photoSizeEmpty","params":[{"name":"type","type":"string"}],"type":"PhotoSize"},{"id":"2009052699","predicate":"photoSize","params":[{"name":"type","type":"string"},{"name":"location","type":"FileLocation"},{"name":"w","type":"int"},{"name":"h","type":"int"},{"name":"size","type":"int"}],"type":"PhotoSize"},{"id":"-374917894","predicate":"photoCachedSize","params":[{"name":"type","type":"string"},{"name":"location","type":"FileLocation"},{"name":"w","type":"int"},{"name":"h","type":"int"},{"name":"bytes","type":"bytes"}],"type":"PhotoSize"},{"id":"-1056548696","predicate":"videoEmpty","params":[{"name":"id","type":"long"}],"type":"Video"},{"id":"1510253727","predicate":"video","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"user_id","type":"int"},{"name":"date","type":"int"},{"name":"caption","type":"string"},{"name":"duration","type":"int"},{"name":"size","type":"int"},{"name":"thumb","type":"PhotoSize"},{"name":"dc_id","type":"int"},{"name":"w","type":"int"},{"name":"h","type":"int"}],"type":"Video"},{"id":"286776671","predicate":"geoPointEmpty","params":[],"type":"GeoPoint"},{"id":"541710092","predicate":"geoPoint","params":[{"name":"long","type":"double"},{"name":"lat","type":"double"}],"type":"GeoPoint"},{"id":"-486486981","predicate":"auth.checkedPhone","params":[{"name":"phone_registered","type":"Bool"},{"name":"phone_invited","type":"Bool"}],"type":"auth.CheckedPhone"},{"id":"571849917","predicate":"auth.sentCode","params":[{"name":"phone_registered","type":"Bool"},{"name":"phone_code_hash","type":"string"}],"type":"auth.SentCode"},{"id":"-155815004","predicate":"auth.authorization","params":[{"name":"expires","type":"int"},{"name":"user","type":"User"}],"type":"auth.Authorization"},{"id":"-543777747","predicate":"auth.exportedAuthorization","params":[{"name":"id","type":"int"},{"name":"bytes","type":"bytes"}],"type":"auth.ExportedAuthorization"},{"id":"-1195615476","predicate":"inputNotifyPeer","params":[{"name":"peer","type":"InputPeer"}],"type":"InputNotifyPeer"},{"id":"423314455","predicate":"inputNotifyUsers","params":[],"type":"InputNotifyPeer"},{"id":"1251338318","predicate":"inputNotifyChats","params":[],"type":"InputNotifyPeer"},{"id":"-1540769658","predicate":"inputNotifyAll","params":[],"type":"InputNotifyPeer"},{"id":"-265263912","predicate":"inputPeerNotifyEventsEmpty","params":[],"type":"InputPeerNotifyEvents"},{"id":"-395694988","predicate":"inputPeerNotifyEventsAll","params":[],"type":"InputPeerNotifyEvents"},{"id":"1185074840","predicate":"inputPeerNotifySettings","params":[{"name":"mute_until","type":"int"},{"name":"sound","type":"string"},{"name":"show_previews","type":"Bool"},{"name":"events_mask","type":"int"}],"type":"InputPeerNotifySettings"},{"id":"-1378534221","predicate":"peerNotifyEventsEmpty","params":[],"type":"PeerNotifyEvents"},{"id":"1830677896","predicate":"peerNotifyEventsAll","params":[],"type":"PeerNotifyEvents"},{"id":"1889961234","predicate":"peerNotifySettingsEmpty","params":[],"type":"PeerNotifySettings"},{"id":"-1923214866","predicate":"peerNotifySettings","params":[{"name":"mute_until","type":"int"},{"name":"sound","type":"string"},{"name":"show_previews","type":"Bool"},{"name":"events_mask","type":"int"}],"type":"PeerNotifySettings"},{"id":"-860866985","predicate":"wallPaper","params":[{"name":"id","type":"int"},{"name":"title","type":"string"},{"name":"sizes","type":"Vector"},{"name":"color","type":"int"}],"type":"WallPaper"},{"id":"1997575642","predicate":"userFull","params":[{"name":"user","type":"User"},{"name":"link","type":"contacts.Link"},{"name":"profile_photo","type":"Photo"},{"name":"notify_settings","type":"PeerNotifySettings"},{"name":"blocked","type":"Bool"},{"name":"real_first_name","type":"string"},{"name":"real_last_name","type":"string"}],"type":"UserFull"},{"id":"-116274796","predicate":"contact","params":[{"name":"user_id","type":"int"},{"name":"mutual","type":"Bool"}],"type":"Contact"},{"id":"-805141448","predicate":"importedContact","params":[{"name":"user_id","type":"int"},{"name":"client_id","type":"long"}],"type":"ImportedContact"},{"id":"1444661369","predicate":"contactBlocked","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"}],"type":"ContactBlocked"},{"id":"-360210539","predicate":"contactFound","params":[{"name":"user_id","type":"int"}],"type":"ContactFound"},{"id":"1038193057","predicate":"contactSuggested","params":[{"name":"user_id","type":"int"},{"name":"mutual_contacts","type":"int"}],"type":"ContactSuggested"},{"id":"-1434994573","predicate":"contactStatus","params":[{"name":"user_id","type":"int"},{"name":"expires","type":"int"}],"type":"ContactStatus"},{"id":"909233996","predicate":"chatLocated","params":[{"name":"chat_id","type":"int"},{"name":"distance","type":"int"}],"type":"ChatLocated"},{"id":"322183672","predicate":"contacts.foreignLinkUnknown","params":[],"type":"contacts.ForeignLink"},{"id":"-1484775609","predicate":"contacts.foreignLinkRequested","params":[{"name":"has_phone","type":"Bool"}],"type":"contacts.ForeignLink"},{"id":"468356321","predicate":"contacts.foreignLinkMutual","params":[],"type":"contacts.ForeignLink"},{"id":"-768992160","predicate":"contacts.myLinkEmpty","params":[],"type":"contacts.MyLink"},{"id":"1818882030","predicate":"contacts.myLinkRequested","params":[{"name":"contact","type":"Bool"}],"type":"contacts.MyLink"},{"id":"-1035932711","predicate":"contacts.myLinkContact","params":[],"type":"contacts.MyLink"},{"id":"-322001931","predicate":"contacts.link","params":[{"name":"my_link","type":"contacts.MyLink"},{"name":"foreign_link","type":"contacts.ForeignLink"},{"name":"user","type":"User"}],"type":"contacts.Link"},{"id":"1871416498","predicate":"contacts.contacts","params":[{"name":"contacts","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.Contacts"},{"id":"-1219778094","predicate":"contacts.contactsNotModified","params":[],"type":"contacts.Contacts"},{"id":"-775091636","predicate":"contacts.importedContacts","params":[{"name":"imported","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.ImportedContacts"},{"id":"471043349","predicate":"contacts.blocked","params":[{"name":"blocked","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.Blocked"},{"id":"-1878523231","predicate":"contacts.blockedSlice","params":[{"name":"count","type":"int"},{"name":"blocked","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.Blocked"},{"id":"90570766","predicate":"contacts.found","params":[{"name":"results","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.Found"},{"id":"1447681221","predicate":"contacts.suggested","params":[{"name":"results","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.Suggested"},{"id":"364538944","predicate":"messages.dialogs","params":[{"name":"dialogs","type":"Vector"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Dialogs"},{"id":"1910543603","predicate":"messages.dialogsSlice","params":[{"name":"count","type":"int"},{"name":"dialogs","type":"Vector"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Dialogs"},{"id":"-1938715001","predicate":"messages.messages","params":[{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Messages"},{"id":"189033187","predicate":"messages.messagesSlice","params":[{"name":"count","type":"int"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Messages"},{"id":"1062078024","predicate":"messages.messageEmpty","params":[],"type":"messages.Message"},{"id":"-7289833","predicate":"messages.message","params":[{"name":"message","type":"Message"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Message"},{"id":"-1768654661","predicate":"messages.statedMessages","params":[{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"},{"name":"pts","type":"int"},{"name":"seq","type":"int"}],"type":"messages.StatedMessages"},{"id":"-797251802","predicate":"messages.statedMessage","params":[{"name":"message","type":"Message"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"},{"name":"pts","type":"int"},{"name":"seq","type":"int"}],"type":"messages.StatedMessage"},{"id":"-772484260","predicate":"messages.sentMessage","params":[{"name":"id","type":"int"},{"name":"date","type":"int"},{"name":"pts","type":"int"},{"name":"seq","type":"int"}],"type":"messages.SentMessage"},{"id":"1089011754","predicate":"messages.chat","params":[{"name":"chat","type":"Chat"},{"name":"users","type":"Vector"}],"type":"messages.Chat"},{"id":"-2125411368","predicate":"messages.chats","params":[{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Chats"},{"id":"-438840932","predicate":"messages.chatFull","params":[{"name":"full_chat","type":"ChatFull"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.ChatFull"},{"id":"-1210173710","predicate":"messages.affectedHistory","params":[{"name":"pts","type":"int"},{"name":"seq","type":"int"},{"name":"offset","type":"int"}],"type":"messages.AffectedHistory"},{"id":"1474492012","predicate":"inputMessagesFilterEmpty","params":[],"type":"MessagesFilter"},{"id":"-1777752804","predicate":"inputMessagesFilterPhotos","params":[],"type":"MessagesFilter"},{"id":"-1614803355","predicate":"inputMessagesFilterVideo","params":[],"type":"MessagesFilter"},{"id":"1458172132","predicate":"inputMessagesFilterPhotoVideo","params":[],"type":"MessagesFilter"},{"id":"20626867","predicate":"updateNewMessage","params":[{"name":"message","type":"Message"},{"name":"pts","type":"int"}],"type":"Update"},{"id":"1318109142","predicate":"updateMessageID","params":[{"name":"id","type":"int"},{"name":"random_id","type":"long"}],"type":"Update"},{"id":"-966484431","predicate":"updateReadMessages","params":[{"name":"messages","type":"Vector"},{"name":"pts","type":"int"}],"type":"Update"},{"id":"-1456734682","predicate":"updateDeleteMessages","params":[{"name":"messages","type":"Vector"},{"name":"pts","type":"int"}],"type":"Update"},{"id":"-782376883","predicate":"updateRestoreMessages","params":[{"name":"messages","type":"Vector"},{"name":"pts","type":"int"}],"type":"Update"},{"id":"1806337288","predicate":"updateUserTyping","params":[{"name":"user_id","type":"int"}],"type":"Update"},{"id":"1011273702","predicate":"updateChatUserTyping","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"}],"type":"Update"},{"id":"125178264","predicate":"updateChatParticipants","params":[{"name":"participants","type":"ChatParticipants"}],"type":"Update"},{"id":"469489699","predicate":"updateUserStatus","params":[{"name":"user_id","type":"int"},{"name":"status","type":"UserStatus"}],"type":"Update"},{"id":"-635250259","predicate":"updateUserName","params":[{"name":"user_id","type":"int"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"Update"},{"id":"-1791935732","predicate":"updateUserPhoto","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"},{"name":"photo","type":"UserProfilePhoto"},{"name":"previous","type":"Bool"}],"type":"Update"},{"id":"628472761","predicate":"updateContactRegistered","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"}],"type":"Update"},{"id":"1369737882","predicate":"updateContactLink","params":[{"name":"user_id","type":"int"},{"name":"my_link","type":"contacts.MyLink"},{"name":"foreign_link","type":"contacts.ForeignLink"}],"type":"Update"},{"id":"1869154659","predicate":"updateActivation","params":[{"name":"user_id","type":"int"}],"type":"Update"},{"id":"-1895411046","predicate":"updateNewAuthorization","params":[{"name":"auth_key_id","type":"long"},{"name":"date","type":"int"},{"name":"device","type":"string"},{"name":"location","type":"string"}],"type":"Update"},{"id":"-1519637954","predicate":"updates.state","params":[{"name":"pts","type":"int"},{"name":"qts","type":"int"},{"name":"date","type":"int"},{"name":"seq","type":"int"},{"name":"unread_count","type":"int"}],"type":"updates.State"},{"id":"1567990072","predicate":"updates.differenceEmpty","params":[{"name":"date","type":"int"},{"name":"seq","type":"int"}],"type":"updates.Difference"},{"id":"16030880","predicate":"updates.difference","params":[{"name":"new_messages","type":"Vector"},{"name":"new_encrypted_messages","type":"Vector"},{"name":"other_updates","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"},{"name":"state","type":"updates.State"}],"type":"updates.Difference"},{"id":"-1459938943","predicate":"updates.differenceSlice","params":[{"name":"new_messages","type":"Vector"},{"name":"new_encrypted_messages","type":"Vector"},{"name":"other_updates","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"},{"name":"intermediate_state","type":"updates.State"}],"type":"updates.Difference"},{"id":"-484987010","predicate":"updatesTooLong","params":[],"type":"Updates"},{"id":"-738961532","predicate":"updateShortMessage","params":[{"name":"id","type":"int"},{"name":"from_id","type":"int"},{"name":"message","type":"string"},{"name":"pts","type":"int"},{"name":"date","type":"int"},{"name":"seq","type":"int"}],"type":"Updates"},{"id":"724548942","predicate":"updateShortChatMessage","params":[{"name":"id","type":"int"},{"name":"from_id","type":"int"},{"name":"chat_id","type":"int"},{"name":"message","type":"string"},{"name":"pts","type":"int"},{"name":"date","type":"int"},{"name":"seq","type":"int"}],"type":"Updates"},{"id":"2027216577","predicate":"updateShort","params":[{"name":"update","type":"Update"},{"name":"date","type":"int"}],"type":"Updates"},{"id":"1918567619","predicate":"updatesCombined","params":[{"name":"updates","type":"Vector"},{"name":"users","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"date","type":"int"},{"name":"seq_start","type":"int"},{"name":"seq","type":"int"}],"type":"Updates"},{"id":"1957577280","predicate":"updates","params":[{"name":"updates","type":"Vector"},{"name":"users","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"date","type":"int"},{"name":"seq","type":"int"}],"type":"Updates"},{"id":"-1916114267","predicate":"photos.photos","params":[{"name":"photos","type":"Vector"},{"name":"users","type":"Vector"}],"type":"photos.Photos"},{"id":"352657236","predicate":"photos.photosSlice","params":[{"name":"count","type":"int"},{"name":"photos","type":"Vector"},{"name":"users","type":"Vector"}],"type":"photos.Photos"},{"id":"539045032","predicate":"photos.photo","params":[{"name":"photo","type":"Photo"},{"name":"users","type":"Vector"}],"type":"photos.Photo"},{"id":"157948117","predicate":"upload.file","params":[{"name":"type","type":"storage.FileType"},{"name":"mtime","type":"int"},{"name":"bytes","type":"bytes"}],"type":"upload.File"},{"id":"784507964","predicate":"dcOption","params":[{"name":"id","type":"int"},{"name":"hostname","type":"string"},{"name":"ip_address","type":"string"},{"name":"port","type":"int"}],"type":"DcOption"},{"id":"590174469","predicate":"config","params":[{"name":"date","type":"int"},{"name":"test_mode","type":"Bool"},{"name":"this_dc","type":"int"},{"name":"dc_options","type":"Vector"},{"name":"chat_size_max","type":"int"}],"type":"Config"},{"id":"-1910892683","predicate":"nearestDc","params":[{"name":"country","type":"string"},{"name":"this_dc","type":"int"},{"name":"nearest_dc","type":"int"}],"type":"NearestDc"},{"id":"-1987579119","predicate":"help.appUpdate","params":[{"name":"id","type":"int"},{"name":"critical","type":"Bool"},{"name":"url","type":"string"},{"name":"text","type":"string"}],"type":"help.AppUpdate"},{"id":"-1000708810","predicate":"help.noAppUpdate","params":[],"type":"help.AppUpdate"},{"id":"415997816","predicate":"help.inviteText","params":[{"name":"message","type":"string"}],"type":"help.InviteText"},{"id":"1047852486","predicate":"messages.statedMessagesLinks","params":[{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"},{"name":"links","type":"Vector"},{"name":"pts","type":"int"},{"name":"seq","type":"int"}],"type":"messages.StatedMessages"},{"id":"-1448138623","predicate":"messages.statedMessageLink","params":[{"name":"message","type":"Message"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"},{"name":"links","type":"Vector"},{"name":"pts","type":"int"},{"name":"seq","type":"int"}],"type":"messages.StatedMessage"},{"id":"-371504577","predicate":"messages.sentMessageLink","params":[{"name":"id","type":"int"},{"name":"date","type":"int"},{"name":"pts","type":"int"},{"name":"seq","type":"int"},{"name":"links","type":"Vector"}],"type":"messages.SentMessage"},{"id":"1960072954","predicate":"inputGeoChat","params":[{"name":"chat_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputGeoChat"},{"id":"1301143240","predicate":"inputNotifyGeoChatPeer","params":[{"name":"peer","type":"InputGeoChat"}],"type":"InputNotifyPeer"},{"id":"1978329690","predicate":"geoChat","params":[{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"title","type":"string"},{"name":"address","type":"string"},{"name":"venue","type":"string"},{"name":"geo","type":"GeoPoint"},{"name":"photo","type":"ChatPhoto"},{"name":"participants_count","type":"int"},{"name":"date","type":"int"},{"name":"checked_in","type":"Bool"},{"name":"version","type":"int"}],"type":"Chat"},{"id":"1613830811","predicate":"geoChatMessageEmpty","params":[{"name":"chat_id","type":"int"},{"name":"id","type":"int"}],"type":"GeoChatMessage"},{"id":"1158019297","predicate":"geoChatMessage","params":[{"name":"chat_id","type":"int"},{"name":"id","type":"int"},{"name":"from_id","type":"int"},{"name":"date","type":"int"},{"name":"message","type":"string"},{"name":"media","type":"MessageMedia"}],"type":"GeoChatMessage"},{"id":"-749755826","predicate":"geoChatMessageService","params":[{"name":"chat_id","type":"int"},{"name":"id","type":"int"},{"name":"from_id","type":"int"},{"name":"date","type":"int"},{"name":"action","type":"MessageAction"}],"type":"GeoChatMessage"},{"id":"397498251","predicate":"geochats.statedMessage","params":[{"name":"message","type":"GeoChatMessage"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"},{"name":"seq","type":"int"}],"type":"geochats.StatedMessage"},{"id":"1224651367","predicate":"geochats.located","params":[{"name":"results","type":"Vector"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"geochats.Located"},{"id":"-783127119","predicate":"geochats.messages","params":[{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"geochats.Messages"},{"id":"-1135057944","predicate":"geochats.messagesSlice","params":[{"name":"count","type":"int"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"geochats.Messages"},{"id":"1862504124","predicate":"messageActionGeoChatCreate","params":[{"name":"title","type":"string"},{"name":"address","type":"string"}],"type":"MessageAction"},{"id":"209540062","predicate":"messageActionGeoChatCheckin","params":[],"type":"MessageAction"},{"id":"1516823543","predicate":"updateNewGeoChatMessage","params":[{"name":"message","type":"GeoChatMessage"}],"type":"Update"},{"id":"1662091044","predicate":"wallPaperSolid","params":[{"name":"id","type":"int"},{"name":"title","type":"string"},{"name":"bg_color","type":"int"},{"name":"color","type":"int"}],"type":"WallPaper"},{"id":"314359194","predicate":"updateNewEncryptedMessage","params":[{"name":"message","type":"EncryptedMessage"},{"name":"qts","type":"int"}],"type":"Update"},{"id":"386986326","predicate":"updateEncryptedChatTyping","params":[{"name":"chat_id","type":"int"}],"type":"Update"},{"id":"-1264392051","predicate":"updateEncryption","params":[{"name":"chat","type":"EncryptedChat"},{"name":"date","type":"int"}],"type":"Update"},{"id":"956179895","predicate":"updateEncryptedMessagesRead","params":[{"name":"chat_id","type":"int"},{"name":"max_date","type":"int"},{"name":"date","type":"int"}],"type":"Update"},{"id":"-1417756512","predicate":"encryptedChatEmpty","params":[{"name":"id","type":"int"}],"type":"EncryptedChat"},{"id":"1006044124","predicate":"encryptedChatWaiting","params":[{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"admin_id","type":"int"},{"name":"participant_id","type":"int"}],"type":"EncryptedChat"},{"id":"-39213129","predicate":"encryptedChatRequested","params":[{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"admin_id","type":"int"},{"name":"participant_id","type":"int"},{"name":"g_a","type":"bytes"},{"name":"nonce","type":"bytes"}],"type":"EncryptedChat"},{"id":"1711395151","predicate":"encryptedChat","params":[{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"admin_id","type":"int"},{"name":"participant_id","type":"int"},{"name":"g_a_or_b","type":"bytes"},{"name":"nonce","type":"bytes"},{"name":"key_fingerprint","type":"long"}],"type":"EncryptedChat"},{"id":"332848423","predicate":"encryptedChatDiscarded","params":[{"name":"id","type":"int"}],"type":"EncryptedChat"},{"id":"-247351839","predicate":"inputEncryptedChat","params":[{"name":"chat_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputEncryptedChat"},{"id":"-1038136962","predicate":"encryptedFileEmpty","params":[],"type":"EncryptedFile"},{"id":"1248893260","predicate":"encryptedFile","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"size","type":"int"},{"name":"dc_id","type":"int"},{"name":"key_fingerprint","type":"int"}],"type":"EncryptedFile"},{"id":"406307684","predicate":"inputEncryptedFileEmpty","params":[],"type":"InputEncryptedFile"},{"id":"1690108678","predicate":"inputEncryptedFileUploaded","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"md5_checksum","type":"string"},{"name":"key_fingerprint","type":"int"}],"type":"InputEncryptedFile"},{"id":"1511503333","predicate":"inputEncryptedFile","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputEncryptedFile"},{"id":"-182231723","predicate":"inputEncryptedFileLocation","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputFileLocation"},{"id":"-317144808","predicate":"encryptedMessage","params":[{"name":"random_id","type":"long"},{"name":"chat_id","type":"int"},{"name":"date","type":"int"},{"name":"bytes","type":"bytes"},{"name":"file","type":"EncryptedFile"}],"type":"EncryptedMessage"},{"id":"594758406","predicate":"encryptedMessageService","params":[{"name":"random_id","type":"long"},{"name":"chat_id","type":"int"},{"name":"date","type":"int"},{"name":"bytes","type":"bytes"}],"type":"EncryptedMessage"},{"id":"-1717290801","predicate":"decryptedMessageLayer","params":[{"name":"layer","type":"int"},{"name":"message","type":"DecryptedMessage"}],"type":"DecryptedMessageLayer"},{"id":"528568095","predicate":"decryptedMessage","params":[{"name":"random_id","type":"long"},{"name":"random_bytes","type":"bytes"},{"name":"message","type":"string"},{"name":"media","type":"DecryptedMessageMedia"}],"type":"DecryptedMessage"},{"id":"-1438109059","predicate":"decryptedMessageService","params":[{"name":"random_id","type":"long"},{"name":"random_bytes","type":"bytes"},{"name":"action","type":"DecryptedMessageAction"}],"type":"DecryptedMessage"},{"id":"144661578","predicate":"decryptedMessageMediaEmpty","params":[],"type":"DecryptedMessageMedia"},{"id":"846826124","predicate":"decryptedMessageMediaPhoto","params":[{"name":"thumb","type":"bytes"},{"name":"thumb_w","type":"int"},{"name":"thumb_h","type":"int"},{"name":"w","type":"int"},{"name":"h","type":"int"},{"name":"size","type":"int"},{"name":"key","type":"bytes"},{"name":"iv","type":"bytes"}],"type":"DecryptedMessageMedia"},{"id":"1290694387","predicate":"decryptedMessageMediaVideo","params":[{"name":"thumb","type":"bytes"},{"name":"thumb_w","type":"int"},{"name":"thumb_h","type":"int"},{"name":"duration","type":"int"},{"name":"w","type":"int"},{"name":"h","type":"int"},{"name":"size","type":"int"},{"name":"key","type":"bytes"},{"name":"iv","type":"bytes"}],"type":"DecryptedMessageMedia"},{"id":"893913689","predicate":"decryptedMessageMediaGeoPoint","params":[{"name":"lat","type":"double"},{"name":"long","type":"double"}],"type":"DecryptedMessageMedia"},{"id":"1485441687","predicate":"decryptedMessageMediaContact","params":[{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"user_id","type":"int"}],"type":"DecryptedMessageMedia"},{"id":"-1586283796","predicate":"decryptedMessageActionSetMessageTTL","params":[{"name":"ttl_seconds","type":"int"}],"type":"DecryptedMessageAction"},{"id":"-1058912715","predicate":"messages.dhConfigNotModified","params":[{"name":"random","type":"bytes"}],"type":"messages.DhConfig"},{"id":"740433629","predicate":"messages.dhConfig","params":[{"name":"g","type":"int"},{"name":"p","type":"bytes"},{"name":"version","type":"int"},{"name":"random","type":"bytes"}],"type":"messages.DhConfig"},{"id":"1443858741","predicate":"messages.sentEncryptedMessage","params":[{"name":"date","type":"int"}],"type":"messages.SentEncryptedMessage"},{"id":"-1802240206","predicate":"messages.sentEncryptedFile","params":[{"name":"date","type":"int"},{"name":"file","type":"EncryptedFile"}],"type":"messages.SentEncryptedMessage"},{"id":"-95482955","predicate":"inputFileBig","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"name","type":"string"}],"type":"InputFile"},{"id":"767652808","predicate":"inputEncryptedFileBigUploaded","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"key_fingerprint","type":"int"}],"type":"InputEncryptedFile"},{"id":"974056226","predicate":"updateChatParticipantAdd","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"version","type":"int"}],"type":"Update"},{"id":"1851755554","predicate":"updateChatParticipantDelete","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"},{"name":"version","type":"int"}],"type":"Update"},{"id":"-1906403213","predicate":"updateDcOptions","params":[{"name":"dc_options","type":"Vector"}],"type":"Update"},{"id":"1638323254","predicate":"inputMediaUploadedAudio","params":[{"name":"file","type":"InputFile"},{"name":"duration","type":"int"}],"type":"InputMedia"},{"id":"-1986820223","predicate":"inputMediaAudio","params":[{"name":"id","type":"InputAudio"}],"type":"InputMedia"},{"id":"887592125","predicate":"inputMediaUploadedDocument","params":[{"name":"file","type":"InputFile"},{"name":"file_name","type":"string"},{"name":"mime_type","type":"string"}],"type":"InputMedia"},{"id":"1044831837","predicate":"inputMediaUploadedThumbDocument","params":[{"name":"file","type":"InputFile"},{"name":"thumb","type":"InputFile"},{"name":"file_name","type":"string"},{"name":"mime_type","type":"string"}],"type":"InputMedia"},{"id":"-779818943","predicate":"inputMediaDocument","params":[{"name":"id","type":"InputDocument"}],"type":"InputMedia"},{"id":"802824708","predicate":"messageMediaDocument","params":[{"name":"document","type":"Document"}],"type":"MessageMedia"},{"id":"-961117440","predicate":"messageMediaAudio","params":[{"name":"audio","type":"Audio"}],"type":"MessageMedia"},{"id":"-648356732","predicate":"inputAudioEmpty","params":[],"type":"InputAudio"},{"id":"2010398975","predicate":"inputAudio","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputAudio"},{"id":"1928391342","predicate":"inputDocumentEmpty","params":[],"type":"InputDocument"},{"id":"410618194","predicate":"inputDocument","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputDocument"},{"id":"1960591437","predicate":"inputAudioFileLocation","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputFileLocation"},{"id":"1313188841","predicate":"inputDocumentFileLocation","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputFileLocation"},{"id":"-1332395189","predicate":"decryptedMessageMediaDocument","params":[{"name":"thumb","type":"bytes"},{"name":"thumb_w","type":"int"},{"name":"thumb_h","type":"int"},{"name":"file_name","type":"string"},{"name":"mime_type","type":"string"},{"name":"size","type":"int"},{"name":"key","type":"bytes"},{"name":"iv","type":"bytes"}],"type":"DecryptedMessageMedia"},{"id":"1619031439","predicate":"decryptedMessageMediaAudio","params":[{"name":"duration","type":"int"},{"name":"size","type":"int"},{"name":"key","type":"bytes"},{"name":"iv","type":"bytes"}],"type":"DecryptedMessageMedia"},{"id":"1483311320","predicate":"audioEmpty","params":[{"name":"id","type":"long"}],"type":"Audio"},{"id":"1114908135","predicate":"audio","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"user_id","type":"int"},{"name":"date","type":"int"},{"name":"duration","type":"int"},{"name":"size","type":"int"},{"name":"dc_id","type":"int"}],"type":"Audio"},{"id":"922273905","predicate":"documentEmpty","params":[{"name":"id","type":"long"}],"type":"Document"},{"id":"-1627626714","predicate":"document","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"user_id","type":"int"},{"name":"date","type":"int"},{"name":"file_name","type":"string"},{"name":"mime_type","type":"string"},{"name":"size","type":"int"},{"name":"thumb","type":"PhotoSize"},{"name":"dc_id","type":"int"}],"type":"Document"}],"methods":[{"id":"-878758099","method":"invokeAfterMsg","params":[{"name":"msg_id","type":"long"},{"name":"query","type":"!X"}],"type":"X"},{"id":"1036301552","method":"invokeAfterMsgs","params":[{"name":"msg_ids","type":"Vector"},{"name":"query","type":"!X"}],"type":"X"},{"id":"1401115413","method":"invokeWithLayer1","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"1877286395","method":"auth.checkPhone","params":[{"name":"phone_number","type":"string"}],"type":"auth.CheckedPhone"},{"id":"1988976461","method":"auth.sendCode","params":[{"name":"phone_number","type":"string"},{"name":"sms_type","type":"int"},{"name":"api_id","type":"int"},{"name":"api_hash","type":"string"},{"name":"lang_code","type":"string"}],"type":"auth.SentCode"},{"id":"63247716","method":"auth.sendCall","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"}],"type":"Bool"},{"id":"453408308","method":"auth.signUp","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"},{"name":"phone_code","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"auth.Authorization"},{"id":"-1126886015","method":"auth.signIn","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"},{"name":"phone_code","type":"string"}],"type":"auth.Authorization"},{"id":"1461180992","method":"auth.logOut","params":[],"type":"Bool"},{"id":"-1616179942","method":"auth.resetAuthorizations","params":[],"type":"Bool"},{"id":"1998331287","method":"auth.sendInvites","params":[{"name":"phone_numbers","type":"Vector"},{"name":"message","type":"string"}],"type":"Bool"},{"id":"-440401971","method":"auth.exportAuthorization","params":[{"name":"dc_id","type":"int"}],"type":"auth.ExportedAuthorization"},{"id":"-470837741","method":"auth.importAuthorization","params":[{"name":"id","type":"int"},{"name":"bytes","type":"bytes"}],"type":"auth.Authorization"},{"id":"1147957548","method":"account.registerDevice","params":[{"name":"token_type","type":"int"},{"name":"token","type":"string"},{"name":"device_model","type":"string"},{"name":"system_version","type":"string"},{"name":"app_version","type":"string"},{"name":"app_sandbox","type":"Bool"},{"name":"lang_code","type":"string"}],"type":"Bool"},{"id":"1707432768","method":"account.unregisterDevice","params":[{"name":"token_type","type":"int"},{"name":"token","type":"string"}],"type":"Bool"},{"id":"-2067899501","method":"account.updateNotifySettings","params":[{"name":"peer","type":"InputNotifyPeer"},{"name":"settings","type":"InputPeerNotifySettings"}],"type":"Bool"},{"id":"313765169","method":"account.getNotifySettings","params":[{"name":"peer","type":"InputNotifyPeer"}],"type":"PeerNotifySettings"},{"id":"-612493497","method":"account.resetNotifySettings","params":[],"type":"Bool"},{"id":"-259486360","method":"account.updateProfile","params":[{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"User"},{"id":"1713919532","method":"account.updateStatus","params":[{"name":"offline","type":"Bool"}],"type":"Bool"},{"id":"-1068696894","method":"account.getWallPapers","params":[],"type":"Vector"},{"id":"227648840","method":"users.getUsers","params":[{"name":"id","type":"Vector"}],"type":"Vector"},{"id":"-902781519","method":"users.getFullUser","params":[{"name":"id","type":"InputUser"}],"type":"UserFull"},{"id":"-995929106","method":"contacts.getStatuses","params":[],"type":"Vector"},{"id":"583445000","method":"contacts.getContacts","params":[{"name":"hash","type":"string"}],"type":"contacts.Contacts"},{"id":"-634342611","method":"contacts.importContacts","params":[{"name":"contacts","type":"Vector"},{"name":"replace","type":"Bool"}],"type":"contacts.ImportedContacts"},{"id":"301470424","method":"contacts.search","params":[{"name":"q","type":"string"},{"name":"limit","type":"int"}],"type":"contacts.Found"},{"id":"-847825880","method":"contacts.getSuggested","params":[{"name":"limit","type":"int"}],"type":"contacts.Suggested"},{"id":"-1902823612","method":"contacts.deleteContact","params":[{"name":"id","type":"InputUser"}],"type":"contacts.Link"},{"id":"1504393374","method":"contacts.deleteContacts","params":[{"name":"id","type":"Vector"}],"type":"Bool"},{"id":"858475004","method":"contacts.block","params":[{"name":"id","type":"InputUser"}],"type":"Bool"},{"id":"-448724803","method":"contacts.unblock","params":[{"name":"id","type":"InputUser"}],"type":"Bool"},{"id":"-176409329","method":"contacts.getBlocked","params":[{"name":"offset","type":"int"},{"name":"limit","type":"int"}],"type":"contacts.Blocked"},{"id":"1109588596","method":"messages.getMessages","params":[{"name":"id","type":"Vector"}],"type":"messages.Messages"},{"id":"-321970698","method":"messages.getDialogs","params":[{"name":"offset","type":"int"},{"name":"max_id","type":"int"},{"name":"limit","type":"int"}],"type":"messages.Dialogs"},{"id":"-1834885329","method":"messages.getHistory","params":[{"name":"peer","type":"InputPeer"},{"name":"offset","type":"int"},{"name":"max_id","type":"int"},{"name":"limit","type":"int"}],"type":"messages.Messages"},{"id":"132772523","method":"messages.search","params":[{"name":"peer","type":"InputPeer"},{"name":"q","type":"string"},{"name":"filter","type":"MessagesFilter"},{"name":"min_date","type":"int"},{"name":"max_date","type":"int"},{"name":"offset","type":"int"},{"name":"max_id","type":"int"},{"name":"limit","type":"int"}],"type":"messages.Messages"},{"id":"-1336990448","method":"messages.readHistory","params":[{"name":"peer","type":"InputPeer"},{"name":"max_id","type":"int"},{"name":"offset","type":"int"}],"type":"messages.AffectedHistory"},{"id":"-185009311","method":"messages.deleteHistory","params":[{"name":"peer","type":"InputPeer"},{"name":"offset","type":"int"}],"type":"messages.AffectedHistory"},{"id":"351460618","method":"messages.deleteMessages","params":[{"name":"id","type":"Vector"}],"type":"Vector"},{"id":"962567550","method":"messages.restoreMessages","params":[{"name":"id","type":"Vector"}],"type":"Vector"},{"id":"682347368","method":"messages.receivedMessages","params":[{"name":"max_id","type":"int"}],"type":"Vector"},{"id":"1905801705","method":"messages.setTyping","params":[{"name":"peer","type":"InputPeer"},{"name":"typing","type":"Bool"}],"type":"Bool"},{"id":"1289620139","method":"messages.sendMessage","params":[{"name":"peer","type":"InputPeer"},{"name":"message","type":"string"},{"name":"random_id","type":"long"}],"type":"messages.SentMessage"},{"id":"-1547149962","method":"messages.sendMedia","params":[{"name":"peer","type":"InputPeer"},{"name":"media","type":"InputMedia"},{"name":"random_id","type":"long"}],"type":"messages.StatedMessage"},{"id":"1363988751","method":"messages.forwardMessages","params":[{"name":"peer","type":"InputPeer"},{"name":"id","type":"Vector"}],"type":"messages.StatedMessages"},{"id":"1013621127","method":"messages.getChats","params":[{"name":"id","type":"Vector"}],"type":"messages.Chats"},{"id":"998448230","method":"messages.getFullChat","params":[{"name":"chat_id","type":"int"}],"type":"messages.ChatFull"},{"id":"-1262720843","method":"messages.editChatTitle","params":[{"name":"chat_id","type":"int"},{"name":"title","type":"string"}],"type":"messages.StatedMessage"},{"id":"-662601187","method":"messages.editChatPhoto","params":[{"name":"chat_id","type":"int"},{"name":"photo","type":"InputChatPhoto"}],"type":"messages.StatedMessage"},{"id":"787082910","method":"messages.addChatUser","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"InputUser"},{"name":"fwd_limit","type":"int"}],"type":"messages.StatedMessage"},{"id":"-1010447069","method":"messages.deleteChatUser","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"InputUser"}],"type":"messages.StatedMessage"},{"id":"1100847854","method":"messages.createChat","params":[{"name":"users","type":"Vector"},{"name":"title","type":"string"}],"type":"messages.StatedMessage"},{"id":"-304838614","method":"updates.getState","params":[],"type":"updates.State"},{"id":"168039573","method":"updates.getDifference","params":[{"name":"pts","type":"int"},{"name":"date","type":"int"},{"name":"qts","type":"int"}],"type":"updates.Difference"},{"id":"-285902432","method":"photos.updateProfilePhoto","params":[{"name":"id","type":"InputPhoto"},{"name":"crop","type":"InputPhotoCrop"}],"type":"UserProfilePhoto"},{"id":"-720397176","method":"photos.uploadProfilePhoto","params":[{"name":"file","type":"InputFile"},{"name":"caption","type":"string"},{"name":"geo_point","type":"InputGeoPoint"},{"name":"crop","type":"InputPhotoCrop"}],"type":"photos.Photo"},{"id":"-1291540959","method":"upload.saveFilePart","params":[{"name":"file_id","type":"long"},{"name":"file_part","type":"int"},{"name":"bytes","type":"bytes"}],"type":"Bool"},{"id":"-475607115","method":"upload.getFile","params":[{"name":"location","type":"InputFileLocation"},{"name":"offset","type":"int"},{"name":"limit","type":"int"}],"type":"upload.File"},{"id":"-990308245","method":"help.getConfig","params":[],"type":"Config"},{"id":"531836966","method":"help.getNearestDc","params":[],"type":"NearestDc"},{"id":"-938300290","method":"help.getAppUpdate","params":[{"name":"device_model","type":"string"},{"name":"system_version","type":"string"},{"name":"app_version","type":"string"},{"name":"lang_code","type":"string"}],"type":"help.AppUpdate"},{"id":"1862465352","method":"help.saveAppLog","params":[{"name":"events","type":"Vector"}],"type":"Bool"},{"id":"-1532407418","method":"help.getInviteText","params":[{"name":"lang_code","type":"string"}],"type":"help.InviteText"},{"id":"-1209117380","method":"photos.getUserPhotos","params":[{"name":"user_id","type":"InputUser"},{"name":"offset","type":"int"},{"name":"max_id","type":"int"},{"name":"limit","type":"int"}],"type":"photos.Photos"},{"id":"681431542","method":"invokeWithLayer2","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"66319602","method":"messages.forwardMessage","params":[{"name":"peer","type":"InputPeer"},{"name":"id","type":"int"},{"name":"random_id","type":"long"}],"type":"messages.StatedMessage"},{"id":"1102776690","method":"messages.sendBroadcast","params":[{"name":"contacts","type":"Vector"},{"name":"message","type":"string"},{"name":"media","type":"InputMedia"}],"type":"messages.StatedMessages"},{"id":"-1220062616","method":"invokeWithLayer3","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"2132356495","method":"geochats.getLocated","params":[{"name":"geo_point","type":"InputGeoPoint"},{"name":"radius","type":"int"},{"name":"limit","type":"int"}],"type":"geochats.Located"},{"id":"-515735953","method":"geochats.getRecents","params":[{"name":"offset","type":"int"},{"name":"limit","type":"int"}],"type":"geochats.Messages"},{"id":"1437853947","method":"geochats.checkin","params":[{"name":"peer","type":"InputGeoChat"}],"type":"geochats.StatedMessage"},{"id":"1730338159","method":"geochats.getFullChat","params":[{"name":"peer","type":"InputGeoChat"}],"type":"messages.ChatFull"},{"id":"1284383347","method":"geochats.editChatTitle","params":[{"name":"peer","type":"InputGeoChat"},{"name":"title","type":"string"},{"name":"address","type":"string"}],"type":"geochats.StatedMessage"},{"id":"903355029","method":"geochats.editChatPhoto","params":[{"name":"peer","type":"InputGeoChat"},{"name":"photo","type":"InputChatPhoto"}],"type":"geochats.StatedMessage"},{"id":"-808598451","method":"geochats.search","params":[{"name":"peer","type":"InputGeoChat"},{"name":"q","type":"string"},{"name":"filter","type":"MessagesFilter"},{"name":"min_date","type":"int"},{"name":"max_date","type":"int"},{"name":"offset","type":"int"},{"name":"max_id","type":"int"},{"name":"limit","type":"int"}],"type":"geochats.Messages"},{"id":"-1254131096","method":"geochats.getHistory","params":[{"name":"peer","type":"InputGeoChat"},{"name":"offset","type":"int"},{"name":"max_id","type":"int"},{"name":"limit","type":"int"}],"type":"geochats.Messages"},{"id":"146319145","method":"geochats.setTyping","params":[{"name":"peer","type":"InputGeoChat"},{"name":"typing","type":"Bool"}],"type":"Bool"},{"id":"102432836","method":"geochats.sendMessage","params":[{"name":"peer","type":"InputGeoChat"},{"name":"message","type":"string"},{"name":"random_id","type":"long"}],"type":"geochats.StatedMessage"},{"id":"-1192173825","method":"geochats.sendMedia","params":[{"name":"peer","type":"InputGeoChat"},{"name":"media","type":"InputMedia"},{"name":"random_id","type":"long"}],"type":"geochats.StatedMessage"},{"id":"235482646","method":"geochats.createGeoChat","params":[{"name":"title","type":"string"},{"name":"geo_point","type":"InputGeoPoint"},{"name":"address","type":"string"},{"name":"venue","type":"string"}],"type":"geochats.StatedMessage"},{"id":"-559885264","method":"invokeWithLayer4","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"1098536878","method":"invokeWithLayer5","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"979686733","method":"invokeWithLayer6","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"-1514252589","method":"invokeWithLayer7","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"651135312","method":"messages.getDhConfig","params":[{"name":"version","type":"int"},{"name":"random_length","type":"int"}],"type":"messages.DhConfig"},{"id":"-162681021","method":"messages.requestEncryption","params":[{"name":"user_id","type":"InputUser"},{"name":"random_id","type":"int"},{"name":"g_a","type":"bytes"}],"type":"EncryptedChat"},{"id":"1035731989","method":"messages.acceptEncryption","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"g_b","type":"bytes"},{"name":"key_fingerprint","type":"long"}],"type":"EncryptedChat"},{"id":"-304536635","method":"messages.discardEncryption","params":[{"name":"chat_id","type":"int"}],"type":"Bool"},{"id":"2031374829","method":"messages.setEncryptedTyping","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"typing","type":"Bool"}],"type":"Bool"},{"id":"2135648522","method":"messages.readEncryptedHistory","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"max_date","type":"int"}],"type":"Bool"},{"id":"-1451792525","method":"messages.sendEncrypted","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"random_id","type":"long"},{"name":"data","type":"bytes"}],"type":"messages.SentEncryptedMessage"},{"id":"-1701831834","method":"messages.sendEncryptedFile","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"random_id","type":"long"},{"name":"data","type":"bytes"},{"name":"file","type":"InputEncryptedFile"}],"type":"messages.SentEncryptedMessage"},{"id":"852769188","method":"messages.sendEncryptedService","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"random_id","type":"long"},{"name":"data","type":"bytes"}],"type":"messages.SentEncryptedMessage"},{"id":"1436924774","method":"messages.receivedQueue","params":[{"name":"max_qts","type":"int"}],"type":"Vector"},{"id":"-374613507","method":"invokeWithLayer8","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"-562337987","method":"upload.saveBigFilePart","params":[{"name":"file_id","type":"long"},{"name":"file_part","type":"int"},{"name":"file_total_parts","type":"int"},{"name":"bytes","type":"bytes"}],"type":"Bool"},{"id":"1769565673","method":"initConnection","params":[{"name":"api_id","type":"int"},{"name":"device_model","type":"string"},{"name":"system_version","type":"string"},{"name":"app_version","type":"string"},{"name":"lang_code","type":"string"},{"name":"query","type":"!X"}],"type":"X"},{"id":"1987140195","method":"invokeWithLayer9","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"962726977","method":"invokeWithLayer10","params":[{"name":"query","type":"!X"}],"type":"X"}]}; + +Config.Schema.API.layer = 10; + +Config.Emoji = {"00a9":["\u00A9",["copyright"]],"00ae":["\u00AE",["registered"]],"203c":["\u203C",["bangbang"]],"2049":["\u2049",["interrobang"]],"2122":["\u2122",["tm"]],"2139":["\u2139",["information_source"]],"2194":["\u2194",["left_right_arrow"]],"2195":["\u2195",["arrow_up_down"]],"2196":["\u2196",["arrow_upper_left"]],"2197":["\u2197",["arrow_upper_right"]],"2198":["\u2198",["arrow_lower_right"]],"2199":["\u2199",["arrow_lower_left"]],"21a9":["\u21A9",["leftwards_arrow_with_hook"]],"21aa":["\u21AA",["arrow_right_hook"]],"231a":["\u231A",["watch"]],"231b":["\u231B",["hourglass"]],"23e9":["\u23E9",["fast_forward"]],"23ea":["\u23EA",["rewind"]],"23eb":["\u23EB",["arrow_double_up"]],"23ec":["\u23EC",["arrow_double_down"]],"23f0":["\u23F0",["alarm_clock"]],"23f3":["\u23F3",["hourglass_flowing_sand"]],"24c2":["\u24C2",["m"]],"25aa":["\u25AA",["black_small_square"]],"25ab":["\u25AB",["white_small_square"]],"25b6":["\u25B6",["arrow_forward"]],"25c0":["\u25C0",["arrow_backward"]],"25fb":["\u25FB",["white_medium_square"]],"25fc":["\u25FC",["black_medium_square"]],"25fd":["\u25FD",["white_medium_small_square"]],"25fe":["\u25FE",["black_medium_small_square"]],"2600":["\u2600",["sunny"]],"2601":["\u2601",["cloud"]],"260e":["\u260E",["phone","telephone"]],"2611":["\u2611",["ballot_box_with_check"]],"2614":["\u2614",["umbrella"]],"2615":["\u2615",["coffee"]],"261d":["\u261D",["point_up"]],"263a":["\u263A",["relaxed"]],"2648":["\u2648",["aries"]],"2649":["\u2649",["taurus"]],"264a":["\u264A",["gemini"]],"264b":["\u264B",["cancer"]],"264c":["\u264C",["leo"]],"264d":["\u264D",["virgo"]],"264e":["\u264E",["libra"]],"264f":["\u264F",["scorpius"]],"2650":["\u2650",["sagittarius"]],"2651":["\u2651",["capricorn"]],"2652":["\u2652",["aquarius"]],"2653":["\u2653",["pisces"]],"2660":["\u2660",["spades"]],"2663":["\u2663",["clubs"]],"2665":["\u2665",["hearts"]],"2666":["\u2666",["diamonds"]],"2668":["\u2668",["hotsprings"]],"267b":["\u267B",["recycle"]],"267f":["\u267F",["wheelchair"]],"2693":["\u2693",["anchor"]],"26a0":["\u26A0",["warning"]],"26a1":["\u26A1",["zap"]],"26aa":["\u26AA",["white_circle"]],"26ab":["\u26AB",["black_circle"]],"26bd":["\u26BD",["soccer"]],"26be":["\u26BE",["baseball"]],"26c4":["\u26C4",["snowman"]],"26c5":["\u26C5",["partly_sunny"]],"26ce":["\u26CE",["ophiuchus"]],"26d4":["\u26D4",["no_entry"]],"26ea":["\u26EA",["church"]],"26f2":["\u26F2",["fountain"]],"26f3":["\u26F3",["golf"]],"26f5":["\u26F5",["boat","sailboat"]],"26fa":["\u26FA",["tent"]],"26fd":["\u26FD",["fuelpump"]],"2702":["\u2702",["scissors"]],"2705":["\u2705",["white_check_mark"]],"2708":["\u2708",["airplane"]],"2709":["\u2709",["email","envelope"]],"270a":["\u270A",["fist"]],"270b":["\u270B",["hand","raised_hand"]],"270c":["\u270C",["v"]],"270f":["\u270F",["pencil2"]],"2712":["\u2712",["black_nib"]],"2714":["\u2714",["heavy_check_mark"]],"2716":["\u2716",["heavy_multiplication_x"]],"2728":["\u2728",["sparkles"]],"2733":["\u2733",["eight_spoked_asterisk"]],"2734":["\u2734",["eight_pointed_black_star"]],"2744":["\u2744",["snowflake"]],"2747":["\u2747",["sparkle"]],"274c":["\u274C",["x"]],"274e":["\u274E",["negative_squared_cross_mark"]],"2753":["\u2753",["question"]],"2754":["\u2754",["grey_question"]],"2755":["\u2755",["grey_exclamation"]],"2757":["\u2757",["exclamation","heavy_exclamation_mark"]],"2764":["\u2764",["heart"],"<3"],"2795":["\u2795",["heavy_plus_sign"]],"2796":["\u2796",["heavy_minus_sign"]],"2797":["\u2797",["heavy_division_sign"]],"27a1":["\u27A1",["arrow_right"]],"27b0":["\u27B0",["curly_loop"]],"27bf":["\u27BF",["loop"]],"2934":["\u2934",["arrow_heading_up"]],"2935":["\u2935",["arrow_heading_down"]],"2b05":["\u2B05",["arrow_left"]],"2b06":["\u2B06",["arrow_up"]],"2b07":["\u2B07",["arrow_down"]],"2b1b":["\u2B1B",["black_large_square"]],"2b1c":["\u2B1C",["white_large_square"]],"2b50":["\u2B50",["star"]],"2b55":["\u2B55",["o"]],"3030":["\u3030",["wavy_dash"]],"303d":["\u303D",["part_alternation_mark"]],"3297":["\u3297",["congratulations"]],"3299":["\u3299",["secret"]],"1f004":["\uD83C\uDC04",["mahjong"]],"1f0cf":["\uD83C\uDCCF",["black_joker"]],"1f170":["\uD83C\uDD70",["a"]],"1f171":["\uD83C\uDD71",["b"]],"1f17e":["\uD83C\uDD7E",["o2"]],"1f17f":["\uD83C\uDD7F",["parking"]],"1f18e":["\uD83C\uDD8E",["ab"]],"1f191":["\uD83C\uDD91",["cl"]],"1f192":["\uD83C\uDD92",["cool"]],"1f193":["\uD83C\uDD93",["free"]],"1f194":["\uD83C\uDD94",["id"]],"1f195":["\uD83C\uDD95",["new"]],"1f196":["\uD83C\uDD96",["ng"]],"1f197":["\uD83C\uDD97",["ok"]],"1f198":["\uD83C\uDD98",["sos"]],"1f199":["\uD83C\uDD99",["up"]],"1f19a":["\uD83C\uDD9A",["vs"]],"1f201":["\uD83C\uDE01",["koko"]],"1f202":["\uD83C\uDE02",["sa"]],"1f21a":["\uD83C\uDE1A",["u7121"]],"1f22f":["\uD83C\uDE2F",["u6307"]],"1f232":["\uD83C\uDE32",["u7981"]],"1f233":["\uD83C\uDE33",["u7a7a"]],"1f234":["\uD83C\uDE34",["u5408"]],"1f235":["\uD83C\uDE35",["u6e80"]],"1f236":["\uD83C\uDE36",["u6709"]],"1f237":["\uD83C\uDE37",["u6708"]],"1f238":["\uD83C\uDE38",["u7533"]],"1f239":["\uD83C\uDE39",["u5272"]],"1f23a":["\uD83C\uDE3A",["u55b6"]],"1f250":["\uD83C\uDE50",["ideograph_advantage"]],"1f251":["\uD83C\uDE51",["accept"]],"1f300":["\uD83C\uDF00",["cyclone"]],"1f301":["\uD83C\uDF01",["foggy"]],"1f302":["\uD83C\uDF02",["closed_umbrella"]],"1f303":["\uD83C\uDF03",["stars"]],"1f304":["\uD83C\uDF04",["sunrise_over_mountains"]],"1f305":["\uD83C\uDF05",["sunrise"]],"1f306":["\uD83C\uDF06",["city_sunset"]],"1f307":["\uD83C\uDF07",["city_sunrise"]],"1f308":["\uD83C\uDF08",["rainbow"]],"1f309":["\uD83C\uDF09",["bridge_at_night"]],"1f30a":["\uD83C\uDF0A",["ocean"]],"1f30b":["\uD83C\uDF0B",["volcano"]],"1f30c":["\uD83C\uDF0C",["milky_way"]],"1f30d":["\uD83C\uDF0D",["earth_africa"]],"1f30e":["\uD83C\uDF0E",["earth_americas"]],"1f30f":["\uD83C\uDF0F",["earth_asia"]],"1f310":["\uD83C\uDF10",["globe_with_meridians"]],"1f311":["\uD83C\uDF11",["new_moon"]],"1f312":["\uD83C\uDF12",["waxing_crescent_moon"]],"1f313":["\uD83C\uDF13",["first_quarter_moon"]],"1f314":["\uD83C\uDF14",["moon","waxing_gibbous_moon"]],"1f315":["\uD83C\uDF15",["full_moon"]],"1f316":["\uD83C\uDF16",["waning_gibbous_moon"]],"1f317":["\uD83C\uDF17",["last_quarter_moon"]],"1f318":["\uD83C\uDF18",["waning_crescent_moon"]],"1f319":["\uD83C\uDF19",["crescent_moon"]],"1f31a":["\uD83C\uDF1A",["new_moon_with_face"]],"1f31b":["\uD83C\uDF1B",["first_quarter_moon_with_face"]],"1f31c":["\uD83C\uDF1C",["last_quarter_moon_with_face"]],"1f31d":["\uD83C\uDF1D",["full_moon_with_face"]],"1f31e":["\uD83C\uDF1E",["sun_with_face"]],"1f31f":["\uD83C\uDF1F",["star2"]],"1f330":["\uD83C\uDF30",["chestnut"]],"1f331":["\uD83C\uDF31",["seedling"]],"1f332":["\uD83C\uDF32",["evergreen_tree"]],"1f333":["\uD83C\uDF33",["deciduous_tree"]],"1f334":["\uD83C\uDF34",["palm_tree"]],"1f335":["\uD83C\uDF35",["cactus"]],"1f337":["\uD83C\uDF37",["tulip"]],"1f338":["\uD83C\uDF38",["cherry_blossom"]],"1f339":["\uD83C\uDF39",["rose"]],"1f33a":["\uD83C\uDF3A",["hibiscus"]],"1f33b":["\uD83C\uDF3B",["sunflower"]],"1f33c":["\uD83C\uDF3C",["blossom"]],"1f33d":["\uD83C\uDF3D",["corn"]],"1f33e":["\uD83C\uDF3E",["ear_of_rice"]],"1f33f":["\uD83C\uDF3F",["herb"]],"1f340":["\uD83C\uDF40",["four_leaf_clover"]],"1f341":["\uD83C\uDF41",["maple_leaf"]],"1f342":["\uD83C\uDF42",["fallen_leaf"]],"1f343":["\uD83C\uDF43",["leaves"]],"1f344":["\uD83C\uDF44",["mushroom"]],"1f345":["\uD83C\uDF45",["tomato"]],"1f346":["\uD83C\uDF46",["eggplant"]],"1f347":["\uD83C\uDF47",["grapes"]],"1f348":["\uD83C\uDF48",["melon"]],"1f349":["\uD83C\uDF49",["watermelon"]],"1f34a":["\uD83C\uDF4A",["tangerine"]],"1f34b":["\uD83C\uDF4B",["lemon"]],"1f34c":["\uD83C\uDF4C",["banana"]],"1f34d":["\uD83C\uDF4D",["pineapple"]],"1f34e":["\uD83C\uDF4E",["apple"]],"1f34f":["\uD83C\uDF4F",["green_apple"]],"1f350":["\uD83C\uDF50",["pear"]],"1f351":["\uD83C\uDF51",["peach"]],"1f352":["\uD83C\uDF52",["cherries"]],"1f353":["\uD83C\uDF53",["strawberry"]],"1f354":["\uD83C\uDF54",["hamburger"]],"1f355":["\uD83C\uDF55",["pizza"]],"1f356":["\uD83C\uDF56",["meat_on_bone"]],"1f357":["\uD83C\uDF57",["poultry_leg"]],"1f358":["\uD83C\uDF58",["rice_cracker"]],"1f359":["\uD83C\uDF59",["rice_ball"]],"1f35a":["\uD83C\uDF5A",["rice"]],"1f35b":["\uD83C\uDF5B",["curry"]],"1f35c":["\uD83C\uDF5C",["ramen"]],"1f35d":["\uD83C\uDF5D",["spaghetti"]],"1f35e":["\uD83C\uDF5E",["bread"]],"1f35f":["\uD83C\uDF5F",["fries"]],"1f360":["\uD83C\uDF60",["sweet_potato"]],"1f361":["\uD83C\uDF61",["dango"]],"1f362":["\uD83C\uDF62",["oden"]],"1f363":["\uD83C\uDF63",["sushi"]],"1f364":["\uD83C\uDF64",["fried_shrimp"]],"1f365":["\uD83C\uDF65",["fish_cake"]],"1f366":["\uD83C\uDF66",["icecream"]],"1f367":["\uD83C\uDF67",["shaved_ice"]],"1f368":["\uD83C\uDF68",["ice_cream"]],"1f369":["\uD83C\uDF69",["doughnut"]],"1f36a":["\uD83C\uDF6A",["cookie"]],"1f36b":["\uD83C\uDF6B",["chocolate_bar"]],"1f36c":["\uD83C\uDF6C",["candy"]],"1f36d":["\uD83C\uDF6D",["lollipop"]],"1f36e":["\uD83C\uDF6E",["custard"]],"1f36f":["\uD83C\uDF6F",["honey_pot"]],"1f370":["\uD83C\uDF70",["cake"]],"1f371":["\uD83C\uDF71",["bento"]],"1f372":["\uD83C\uDF72",["stew"]],"1f373":["\uD83C\uDF73",["egg"]],"1f374":["\uD83C\uDF74",["fork_and_knife"]],"1f375":["\uD83C\uDF75",["tea"]],"1f376":["\uD83C\uDF76",["sake"]],"1f377":["\uD83C\uDF77",["wine_glass"]],"1f378":["\uD83C\uDF78",["cocktail"]],"1f379":["\uD83C\uDF79",["tropical_drink"]],"1f37a":["\uD83C\uDF7A",["beer"]],"1f37b":["\uD83C\uDF7B",["beers"]],"1f37c":["\uD83C\uDF7C",["baby_bottle"]],"1f380":["\uD83C\uDF80",["ribbon"]],"1f381":["\uD83C\uDF81",["gift"]],"1f382":["\uD83C\uDF82",["birthday"]],"1f383":["\uD83C\uDF83",["jack_o_lantern"]],"1f384":["\uD83C\uDF84",["christmas_tree"]],"1f385":["\uD83C\uDF85",["santa"]],"1f386":["\uD83C\uDF86",["fireworks"]],"1f387":["\uD83C\uDF87",["sparkler"]],"1f388":["\uD83C\uDF88",["balloon"]],"1f389":["\uD83C\uDF89",["tada"]],"1f38a":["\uD83C\uDF8A",["confetti_ball"]],"1f38b":["\uD83C\uDF8B",["tanabata_tree"]],"1f38c":["\uD83C\uDF8C",["crossed_flags"]],"1f38d":["\uD83C\uDF8D",["bamboo"]],"1f38e":["\uD83C\uDF8E",["dolls"]],"1f38f":["\uD83C\uDF8F",["flags"]],"1f390":["\uD83C\uDF90",["wind_chime"]],"1f391":["\uD83C\uDF91",["rice_scene"]],"1f392":["\uD83C\uDF92",["school_satchel"]],"1f393":["\uD83C\uDF93",["mortar_board"]],"1f3a0":["\uD83C\uDFA0",["carousel_horse"]],"1f3a1":["\uD83C\uDFA1",["ferris_wheel"]],"1f3a2":["\uD83C\uDFA2",["roller_coaster"]],"1f3a3":["\uD83C\uDFA3",["fishing_pole_and_fish"]],"1f3a4":["\uD83C\uDFA4",["microphone"]],"1f3a5":["\uD83C\uDFA5",["movie_camera"]],"1f3a6":["\uD83C\uDFA6",["cinema"]],"1f3a7":["\uD83C\uDFA7",["headphones"]],"1f3a8":["\uD83C\uDFA8",["art"]],"1f3a9":["\uD83C\uDFA9",["tophat"]],"1f3aa":["\uD83C\uDFAA",["circus_tent"]],"1f3ab":["\uD83C\uDFAB",["ticket"]],"1f3ac":["\uD83C\uDFAC",["clapper"]],"1f3ad":["\uD83C\uDFAD",["performing_arts"]],"1f3ae":["\uD83C\uDFAE",["video_game"]],"1f3af":["\uD83C\uDFAF",["dart"]],"1f3b0":["\uD83C\uDFB0",["slot_machine"]],"1f3b1":["\uD83C\uDFB1",["8ball"]],"1f3b2":["\uD83C\uDFB2",["game_die"]],"1f3b3":["\uD83C\uDFB3",["bowling"]],"1f3b4":["\uD83C\uDFB4",["flower_playing_cards"]],"1f3b5":["\uD83C\uDFB5",["musical_note"]],"1f3b6":["\uD83C\uDFB6",["notes"]],"1f3b7":["\uD83C\uDFB7",["saxophone"]],"1f3b8":["\uD83C\uDFB8",["guitar"]],"1f3b9":["\uD83C\uDFB9",["musical_keyboard"]],"1f3ba":["\uD83C\uDFBA",["trumpet"]],"1f3bb":["\uD83C\uDFBB",["violin"]],"1f3bc":["\uD83C\uDFBC",["musical_score"]],"1f3bd":["\uD83C\uDFBD",["running_shirt_with_sash"]],"1f3be":["\uD83C\uDFBE",["tennis"]],"1f3bf":["\uD83C\uDFBF",["ski"]],"1f3c0":["\uD83C\uDFC0",["basketball"]],"1f3c1":["\uD83C\uDFC1",["checkered_flag"]],"1f3c2":["\uD83C\uDFC2",["snowboarder"]],"1f3c3":["\uD83C\uDFC3",["runner","running"]],"1f3c4":["\uD83C\uDFC4",["surfer"]],"1f3c6":["\uD83C\uDFC6",["trophy"]],"1f3c7":["\uD83C\uDFC7",["horse_racing"]],"1f3c8":["\uD83C\uDFC8",["football"]],"1f3c9":["\uD83C\uDFC9",["rugby_football"]],"1f3ca":["\uD83C\uDFCA",["swimmer"]],"1f3e0":["\uD83C\uDFE0",["house"]],"1f3e1":["\uD83C\uDFE1",["house_with_garden"]],"1f3e2":["\uD83C\uDFE2",["office"]],"1f3e3":["\uD83C\uDFE3",["post_office"]],"1f3e4":["\uD83C\uDFE4",["european_post_office"]],"1f3e5":["\uD83C\uDFE5",["hospital"]],"1f3e6":["\uD83C\uDFE6",["bank"]],"1f3e7":["\uD83C\uDFE7",["atm"]],"1f3e8":["\uD83C\uDFE8",["hotel"]],"1f3e9":["\uD83C\uDFE9",["love_hotel"]],"1f3ea":["\uD83C\uDFEA",["convenience_store"]],"1f3eb":["\uD83C\uDFEB",["school"]],"1f3ec":["\uD83C\uDFEC",["department_store"]],"1f3ed":["\uD83C\uDFED",["factory"]],"1f3ee":["\uD83C\uDFEE",["izakaya_lantern","lantern"]],"1f3ef":["\uD83C\uDFEF",["japanese_castle"]],"1f3f0":["\uD83C\uDFF0",["european_castle"]],"1f400":["\uD83D\uDC00",["rat"]],"1f401":["\uD83D\uDC01",["mouse2"]],"1f402":["\uD83D\uDC02",["ox"]],"1f403":["\uD83D\uDC03",["water_buffalo"]],"1f404":["\uD83D\uDC04",["cow2"]],"1f405":["\uD83D\uDC05",["tiger2"]],"1f406":["\uD83D\uDC06",["leopard"]],"1f407":["\uD83D\uDC07",["rabbit2"]],"1f408":["\uD83D\uDC08",["cat2"]],"1f409":["\uD83D\uDC09",["dragon"]],"1f40a":["\uD83D\uDC0A",["crocodile"]],"1f40b":["\uD83D\uDC0B",["whale2"]],"1f40c":["\uD83D\uDC0C",["snail"]],"1f40d":["\uD83D\uDC0D",["snake"]],"1f40e":["\uD83D\uDC0E",["racehorse"]],"1f40f":["\uD83D\uDC0F",["ram"]],"1f410":["\uD83D\uDC10",["goat"]],"1f411":["\uD83D\uDC11",["sheep"]],"1f412":["\uD83D\uDC12",["monkey"]],"1f413":["\uD83D\uDC13",["rooster"]],"1f414":["\uD83D\uDC14",["chicken"]],"1f415":["\uD83D\uDC15",["dog2"]],"1f416":["\uD83D\uDC16",["pig2"]],"1f417":["\uD83D\uDC17",["boar"]],"1f418":["\uD83D\uDC18",["elephant"]],"1f419":["\uD83D\uDC19",["octopus"]],"1f41a":["\uD83D\uDC1A",["shell"]],"1f41b":["\uD83D\uDC1B",["bug"]],"1f41c":["\uD83D\uDC1C",["ant"]],"1f41d":["\uD83D\uDC1D",["bee","honeybee"]],"1f41e":["\uD83D\uDC1E",["beetle"]],"1f41f":["\uD83D\uDC1F",["fish"]],"1f420":["\uD83D\uDC20",["tropical_fish"]],"1f421":["\uD83D\uDC21",["blowfish"]],"1f422":["\uD83D\uDC22",["turtle"]],"1f423":["\uD83D\uDC23",["hatching_chick"]],"1f424":["\uD83D\uDC24",["baby_chick"]],"1f425":["\uD83D\uDC25",["hatched_chick"]],"1f426":["\uD83D\uDC26",["bird"]],"1f427":["\uD83D\uDC27",["penguin"]],"1f428":["\uD83D\uDC28",["koala"]],"1f429":["\uD83D\uDC29",["poodle"]],"1f42a":["\uD83D\uDC2A",["dromedary_camel"]],"1f42b":["\uD83D\uDC2B",["camel"]],"1f42c":["\uD83D\uDC2C",["dolphin","flipper"]],"1f42d":["\uD83D\uDC2D",["mouse"]],"1f42e":["\uD83D\uDC2E",["cow"]],"1f42f":["\uD83D\uDC2F",["tiger"]],"1f430":["\uD83D\uDC30",["rabbit"]],"1f431":["\uD83D\uDC31",["cat"]],"1f432":["\uD83D\uDC32",["dragon_face"]],"1f433":["\uD83D\uDC33",["whale"]],"1f434":["\uD83D\uDC34",["horse"]],"1f435":["\uD83D\uDC35",["monkey_face"]],"1f436":["\uD83D\uDC36",["dog"]],"1f437":["\uD83D\uDC37",["pig"]],"1f438":["\uD83D\uDC38",["frog"]],"1f439":["\uD83D\uDC39",["hamster"]],"1f43a":["\uD83D\uDC3A",["wolf"]],"1f43b":["\uD83D\uDC3B",["bear"]],"1f43c":["\uD83D\uDC3C",["panda_face"]],"1f43d":["\uD83D\uDC3D",["pig_nose"]],"1f43e":["\uD83D\uDC3E",["feet","paw_prints"]],"1f440":["\uD83D\uDC40",["eyes"]],"1f442":["\uD83D\uDC42",["ear"]],"1f443":["\uD83D\uDC43",["nose"]],"1f444":["\uD83D\uDC44",["lips"]],"1f445":["\uD83D\uDC45",["tongue"]],"1f446":["\uD83D\uDC46",["point_up_2"]],"1f447":["\uD83D\uDC47",["point_down"]],"1f448":["\uD83D\uDC48",["point_left"]],"1f449":["\uD83D\uDC49",["point_right"]],"1f44a":["\uD83D\uDC4A",["facepunch","punch"]],"1f44b":["\uD83D\uDC4B",["wave"]],"1f44c":["\uD83D\uDC4C",["ok_hand"]],"1f44d":["\uD83D\uDC4D",["+1","thumbsup"]],"1f44e":["\uD83D\uDC4E",["-1","thumbsdown"]],"1f44f":["\uD83D\uDC4F",["clap"]],"1f450":["\uD83D\uDC50",["open_hands"]],"1f451":["\uD83D\uDC51",["crown"]],"1f452":["\uD83D\uDC52",["womans_hat"]],"1f453":["\uD83D\uDC53",["eyeglasses"]],"1f454":["\uD83D\uDC54",["necktie"]],"1f455":["\uD83D\uDC55",["shirt","tshirt"]],"1f456":["\uD83D\uDC56",["jeans"]],"1f457":["\uD83D\uDC57",["dress"]],"1f458":["\uD83D\uDC58",["kimono"]],"1f459":["\uD83D\uDC59",["bikini"]],"1f45a":["\uD83D\uDC5A",["womans_clothes"]],"1f45b":["\uD83D\uDC5B",["purse"]],"1f45c":["\uD83D\uDC5C",["handbag"]],"1f45d":["\uD83D\uDC5D",["pouch"]],"1f45e":["\uD83D\uDC5E",["mans_shoe","shoe"]],"1f45f":["\uD83D\uDC5F",["athletic_shoe"]],"1f460":["\uD83D\uDC60",["high_heel"]],"1f461":["\uD83D\uDC61",["sandal"]],"1f462":["\uD83D\uDC62",["boot"]],"1f463":["\uD83D\uDC63",["footprints"]],"1f464":["\uD83D\uDC64",["bust_in_silhouette"]],"1f465":["\uD83D\uDC65",["busts_in_silhouette"]],"1f466":["\uD83D\uDC66",["boy"]],"1f467":["\uD83D\uDC67",["girl"]],"1f468":["\uD83D\uDC68",["man"]],"1f469":["\uD83D\uDC69",["woman"]],"1f46a":["\uD83D\uDC6A",["family"]],"1f46b":["\uD83D\uDC6B",["couple"]],"1f46c":["\uD83D\uDC6C",["two_men_holding_hands"]],"1f46d":["\uD83D\uDC6D",["two_women_holding_hands"]],"1f46e":["\uD83D\uDC6E",["cop"]],"1f46f":["\uD83D\uDC6F",["dancers"]],"1f470":["\uD83D\uDC70",["bride_with_veil"]],"1f471":["\uD83D\uDC71",["person_with_blond_hair"]],"1f472":["\uD83D\uDC72",["man_with_gua_pi_mao"]],"1f473":["\uD83D\uDC73",["man_with_turban"]],"1f474":["\uD83D\uDC74",["older_man"]],"1f475":["\uD83D\uDC75",["older_woman"]],"1f476":["\uD83D\uDC76",["baby"]],"1f477":["\uD83D\uDC77",["construction_worker"]],"1f478":["\uD83D\uDC78",["princess"]],"1f479":["\uD83D\uDC79",["japanese_ogre"]],"1f47a":["\uD83D\uDC7A",["japanese_goblin"]],"1f47b":["\uD83D\uDC7B",["ghost"]],"1f47c":["\uD83D\uDC7C",["angel"]],"1f47d":["\uD83D\uDC7D",["alien"]],"1f47e":["\uD83D\uDC7E",["space_invader"]],"1f47f":["\uD83D\uDC7F",["imp"]],"1f480":["\uD83D\uDC80",["skull"]],"1f481":["\uD83D\uDC81",["information_desk_person"]],"1f482":["\uD83D\uDC82",["guardsman"]],"1f483":["\uD83D\uDC83",["dancer"]],"1f484":["\uD83D\uDC84",["lipstick"]],"1f485":["\uD83D\uDC85",["nail_care"]],"1f486":["\uD83D\uDC86",["massage"]],"1f487":["\uD83D\uDC87",["haircut"]],"1f488":["\uD83D\uDC88",["barber"]],"1f489":["\uD83D\uDC89",["syringe"]],"1f48a":["\uD83D\uDC8A",["pill"]],"1f48b":["\uD83D\uDC8B",["kiss"]],"1f48c":["\uD83D\uDC8C",["love_letter"]],"1f48d":["\uD83D\uDC8D",["ring"]],"1f48e":["\uD83D\uDC8E",["gem"]],"1f48f":["\uD83D\uDC8F",["couplekiss"]],"1f490":["\uD83D\uDC90",["bouquet"]],"1f491":["\uD83D\uDC91",["couple_with_heart"]],"1f492":["\uD83D\uDC92",["wedding"]],"1f493":["\uD83D\uDC93",["heartbeat"]],"1f494":["\uD83D\uDC94",["broken_heart"],"<\/3"],"1f495":["\uD83D\uDC95",["two_hearts"]],"1f496":["\uD83D\uDC96",["sparkling_heart"]],"1f497":["\uD83D\uDC97",["heartpulse"]],"1f498":["\uD83D\uDC98",["cupid"]],"1f499":["\uD83D\uDC99",["blue_heart"],"<3"],"1f49a":["\uD83D\uDC9A",["green_heart"],"<3"],"1f49b":["\uD83D\uDC9B",["yellow_heart"],"<3"],"1f49c":["\uD83D\uDC9C",["purple_heart"],"<3"],"1f49d":["\uD83D\uDC9D",["gift_heart"]],"1f49e":["\uD83D\uDC9E",["revolving_hearts"]],"1f49f":["\uD83D\uDC9F",["heart_decoration"]],"1f4a0":["\uD83D\uDCA0",["diamond_shape_with_a_dot_inside"]],"1f4a1":["\uD83D\uDCA1",["bulb"]],"1f4a2":["\uD83D\uDCA2",["anger"]],"1f4a3":["\uD83D\uDCA3",["bomb"]],"1f4a4":["\uD83D\uDCA4",["zzz"]],"1f4a5":["\uD83D\uDCA5",["boom","collision"]],"1f4a6":["\uD83D\uDCA6",["sweat_drops"]],"1f4a7":["\uD83D\uDCA7",["droplet"]],"1f4a8":["\uD83D\uDCA8",["dash"]],"1f4a9":["\uD83D\uDCA9",["hankey","poop","shit"]],"1f4aa":["\uD83D\uDCAA",["muscle"]],"1f4ab":["\uD83D\uDCAB",["dizzy"]],"1f4ac":["\uD83D\uDCAC",["speech_balloon"]],"1f4ad":["\uD83D\uDCAD",["thought_balloon"]],"1f4ae":["\uD83D\uDCAE",["white_flower"]],"1f4af":["\uD83D\uDCAF",["100"]],"1f4b0":["\uD83D\uDCB0",["moneybag"]],"1f4b1":["\uD83D\uDCB1",["currency_exchange"]],"1f4b2":["\uD83D\uDCB2",["heavy_dollar_sign"]],"1f4b3":["\uD83D\uDCB3",["credit_card"]],"1f4b4":["\uD83D\uDCB4",["yen"]],"1f4b5":["\uD83D\uDCB5",["dollar"]],"1f4b6":["\uD83D\uDCB6",["euro"]],"1f4b7":["\uD83D\uDCB7",["pound"]],"1f4b8":["\uD83D\uDCB8",["money_with_wings"]],"1f4b9":["\uD83D\uDCB9",["chart"]],"1f4ba":["\uD83D\uDCBA",["seat"]],"1f4bb":["\uD83D\uDCBB",["computer"]],"1f4bc":["\uD83D\uDCBC",["briefcase"]],"1f4bd":["\uD83D\uDCBD",["minidisc"]],"1f4be":["\uD83D\uDCBE",["floppy_disk"]],"1f4bf":["\uD83D\uDCBF",["cd"]],"1f4c0":["\uD83D\uDCC0",["dvd"]],"1f4c1":["\uD83D\uDCC1",["file_folder"]],"1f4c2":["\uD83D\uDCC2",["open_file_folder"]],"1f4c3":["\uD83D\uDCC3",["page_with_curl"]],"1f4c4":["\uD83D\uDCC4",["page_facing_up"]],"1f4c5":["\uD83D\uDCC5",["date"]],"1f4c6":["\uD83D\uDCC6",["calendar"]],"1f4c7":["\uD83D\uDCC7",["card_index"]],"1f4c8":["\uD83D\uDCC8",["chart_with_upwards_trend"]],"1f4c9":["\uD83D\uDCC9",["chart_with_downwards_trend"]],"1f4ca":["\uD83D\uDCCA",["bar_chart"]],"1f4cb":["\uD83D\uDCCB",["clipboard"]],"1f4cc":["\uD83D\uDCCC",["pushpin"]],"1f4cd":["\uD83D\uDCCD",["round_pushpin"]],"1f4ce":["\uD83D\uDCCE",["paperclip"]],"1f4cf":["\uD83D\uDCCF",["straight_ruler"]],"1f4d0":["\uD83D\uDCD0",["triangular_ruler"]],"1f4d1":["\uD83D\uDCD1",["bookmark_tabs"]],"1f4d2":["\uD83D\uDCD2",["ledger"]],"1f4d3":["\uD83D\uDCD3",["notebook"]],"1f4d4":["\uD83D\uDCD4",["notebook_with_decorative_cover"]],"1f4d5":["\uD83D\uDCD5",["closed_book"]],"1f4d6":["\uD83D\uDCD6",["book","open_book"]],"1f4d7":["\uD83D\uDCD7",["green_book"]],"1f4d8":["\uD83D\uDCD8",["blue_book"]],"1f4d9":["\uD83D\uDCD9",["orange_book"]],"1f4da":["\uD83D\uDCDA",["books"]],"1f4db":["\uD83D\uDCDB",["name_badge"]],"1f4dc":["\uD83D\uDCDC",["scroll"]],"1f4dd":["\uD83D\uDCDD",["memo","pencil"]],"1f4de":["\uD83D\uDCDE",["telephone_receiver"]],"1f4df":["\uD83D\uDCDF",["pager"]],"1f4e0":["\uD83D\uDCE0",["fax"]],"1f4e1":["\uD83D\uDCE1",["satellite"]],"1f4e2":["\uD83D\uDCE2",["loudspeaker"]],"1f4e3":["\uD83D\uDCE3",["mega"]],"1f4e4":["\uD83D\uDCE4",["outbox_tray"]],"1f4e5":["\uD83D\uDCE5",["inbox_tray"]],"1f4e6":["\uD83D\uDCE6",["package"]],"1f4e7":["\uD83D\uDCE7",["e-mail"]],"1f4e8":["\uD83D\uDCE8",["incoming_envelope"]],"1f4e9":["\uD83D\uDCE9",["envelope_with_arrow"]],"1f4ea":["\uD83D\uDCEA",["mailbox_closed"]],"1f4eb":["\uD83D\uDCEB",["mailbox"]],"1f4ec":["\uD83D\uDCEC",["mailbox_with_mail"]],"1f4ed":["\uD83D\uDCED",["mailbox_with_no_mail"]],"1f4ee":["\uD83D\uDCEE",["postbox"]],"1f4ef":["\uD83D\uDCEF",["postal_horn"]],"1f4f0":["\uD83D\uDCF0",["newspaper"]],"1f4f1":["\uD83D\uDCF1",["iphone"]],"1f4f2":["\uD83D\uDCF2",["calling"]],"1f4f3":["\uD83D\uDCF3",["vibration_mode"]],"1f4f4":["\uD83D\uDCF4",["mobile_phone_off"]],"1f4f5":["\uD83D\uDCF5",["no_mobile_phones"]],"1f4f6":["\uD83D\uDCF6",["signal_strength"]],"1f4f7":["\uD83D\uDCF7",["camera"]],"1f4f9":["\uD83D\uDCF9",["video_camera"]],"1f4fa":["\uD83D\uDCFA",["tv"]],"1f4fb":["\uD83D\uDCFB",["radio"]],"1f4fc":["\uD83D\uDCFC",["vhs"]],"1f500":["\uD83D\uDD00",["twisted_rightwards_arrows"]],"1f501":["\uD83D\uDD01",["repeat"]],"1f502":["\uD83D\uDD02",["repeat_one"]],"1f503":["\uD83D\uDD03",["arrows_clockwise"]],"1f504":["\uD83D\uDD04",["arrows_counterclockwise"]],"1f505":["\uD83D\uDD05",["low_brightness"]],"1f506":["\uD83D\uDD06",["high_brightness"]],"1f507":["\uD83D\uDD07",["mute"]],"1f509":["\uD83D\uDD09",["sound"]],"1f50a":["\uD83D\uDD0A",["speaker"]],"1f50b":["\uD83D\uDD0B",["battery"]],"1f50c":["\uD83D\uDD0C",["electric_plug"]],"1f50d":["\uD83D\uDD0D",["mag"]],"1f50e":["\uD83D\uDD0E",["mag_right"]],"1f50f":["\uD83D\uDD0F",["lock_with_ink_pen"]],"1f510":["\uD83D\uDD10",["closed_lock_with_key"]],"1f511":["\uD83D\uDD11",["key"]],"1f512":["\uD83D\uDD12",["lock"]],"1f513":["\uD83D\uDD13",["unlock"]],"1f514":["\uD83D\uDD14",["bell"]],"1f515":["\uD83D\uDD15",["no_bell"]],"1f516":["\uD83D\uDD16",["bookmark"]],"1f517":["\uD83D\uDD17",["link"]],"1f518":["\uD83D\uDD18",["radio_button"]],"1f519":["\uD83D\uDD19",["back"]],"1f51a":["\uD83D\uDD1A",["end"]],"1f51b":["\uD83D\uDD1B",["on"]],"1f51c":["\uD83D\uDD1C",["soon"]],"1f51d":["\uD83D\uDD1D",["top"]],"1f51e":["\uD83D\uDD1E",["underage"]],"1f51f":["\uD83D\uDD1F",["keycap_ten"]],"1f520":["\uD83D\uDD20",["capital_abcd"]],"1f521":["\uD83D\uDD21",["abcd"]],"1f522":["\uD83D\uDD22",["1234"]],"1f523":["\uD83D\uDD23",["symbols"]],"1f524":["\uD83D\uDD24",["abc"]],"1f525":["\uD83D\uDD25",["fire"]],"1f526":["\uD83D\uDD26",["flashlight"]],"1f527":["\uD83D\uDD27",["wrench"]],"1f528":["\uD83D\uDD28",["hammer"]],"1f529":["\uD83D\uDD29",["nut_and_bolt"]],"1f52a":["\uD83D\uDD2A",["hocho"]],"1f52b":["\uD83D\uDD2B",["gun"]],"1f52c":["\uD83D\uDD2C",["microscope"]],"1f52d":["\uD83D\uDD2D",["telescope"]],"1f52e":["\uD83D\uDD2E",["crystal_ball"]],"1f52f":["\uD83D\uDD2F",["six_pointed_star"]],"1f530":["\uD83D\uDD30",["beginner"]],"1f531":["\uD83D\uDD31",["trident"]],"1f532":["\uD83D\uDD32",["black_square_button"]],"1f533":["\uD83D\uDD33",["white_square_button"]],"1f534":["\uD83D\uDD34",["red_circle"]],"1f535":["\uD83D\uDD35",["large_blue_circle"]],"1f536":["\uD83D\uDD36",["large_orange_diamond"]],"1f537":["\uD83D\uDD37",["large_blue_diamond"]],"1f538":["\uD83D\uDD38",["small_orange_diamond"]],"1f539":["\uD83D\uDD39",["small_blue_diamond"]],"1f53a":["\uD83D\uDD3A",["small_red_triangle"]],"1f53b":["\uD83D\uDD3B",["small_red_triangle_down"]],"1f53c":["\uD83D\uDD3C",["arrow_up_small"]],"1f53d":["\uD83D\uDD3D",["arrow_down_small"]],"1f550":["\uD83D\uDD50",["clock1"]],"1f551":["\uD83D\uDD51",["clock2"]],"1f552":["\uD83D\uDD52",["clock3"]],"1f553":["\uD83D\uDD53",["clock4"]],"1f554":["\uD83D\uDD54",["clock5"]],"1f555":["\uD83D\uDD55",["clock6"]],"1f556":["\uD83D\uDD56",["clock7"]],"1f557":["\uD83D\uDD57",["clock8"]],"1f558":["\uD83D\uDD58",["clock9"]],"1f559":["\uD83D\uDD59",["clock10"]],"1f55a":["\uD83D\uDD5A",["clock11"]],"1f55b":["\uD83D\uDD5B",["clock12"]],"1f55c":["\uD83D\uDD5C",["clock130"]],"1f55d":["\uD83D\uDD5D",["clock230"]],"1f55e":["\uD83D\uDD5E",["clock330"]],"1f55f":["\uD83D\uDD5F",["clock430"]],"1f560":["\uD83D\uDD60",["clock530"]],"1f561":["\uD83D\uDD61",["clock630"]],"1f562":["\uD83D\uDD62",["clock730"]],"1f563":["\uD83D\uDD63",["clock830"]],"1f564":["\uD83D\uDD64",["clock930"]],"1f565":["\uD83D\uDD65",["clock1030"]],"1f566":["\uD83D\uDD66",["clock1130"]],"1f567":["\uD83D\uDD67",["clock1230"]],"1f5fb":["\uD83D\uDDFB",["mount_fuji"]],"1f5fc":["\uD83D\uDDFC",["tokyo_tower"]],"1f5fd":["\uD83D\uDDFD",["statue_of_liberty"]],"1f5fe":["\uD83D\uDDFE",["japan"]],"1f5ff":["\uD83D\uDDFF",["moyai"]],"1f600":["\uD83D\uDE00",["grinning"]],"1f601":["\uD83D\uDE01",["grin"]],"1f602":["\uD83D\uDE02",["joy"]],"1f603":["\uD83D\uDE03",["smiley"],":)"],"1f604":["\uD83D\uDE04",["smile"],":)"],"1f605":["\uD83D\uDE05",["sweat_smile"]],"1f606":["\uD83D\uDE06",["laughing","satisfied"]],"1f607":["\uD83D\uDE07",["innocent"]],"1f608":["\uD83D\uDE08",["smiling_imp"]],"1f609":["\uD83D\uDE09",["wink"],";)"],"1f60a":["\uD83D\uDE0A",["blush"]],"1f60b":["\uD83D\uDE0B",["yum"]],"1f60c":["\uD83D\uDE0C",["relieved"]],"1f60d":["\uD83D\uDE0D",["heart_eyes"]],"1f60e":["\uD83D\uDE0E",["sunglasses"]],"1f60f":["\uD83D\uDE0F",["smirk"]],"1f610":["\uD83D\uDE10",["neutral_face"]],"1f611":["\uD83D\uDE11",["expressionless"]],"1f612":["\uD83D\uDE12",["unamused"]],"1f613":["\uD83D\uDE13",["sweat"]],"1f614":["\uD83D\uDE14",["pensive"]],"1f615":["\uD83D\uDE15",["confused"]],"1f616":["\uD83D\uDE16",["confounded"]],"1f617":["\uD83D\uDE17",["kissing"]],"1f618":["\uD83D\uDE18",["kissing_heart"]],"1f619":["\uD83D\uDE19",["kissing_smiling_eyes"]],"1f61a":["\uD83D\uDE1A",["kissing_closed_eyes"]],"1f61b":["\uD83D\uDE1B",["stuck_out_tongue"]],"1f61c":["\uD83D\uDE1C",["stuck_out_tongue_winking_eye"],";p"],"1f61d":["\uD83D\uDE1D",["stuck_out_tongue_closed_eyes"]],"1f61e":["\uD83D\uDE1E",["disappointed"],":("],"1f61f":["\uD83D\uDE1F",["worried"]],"1f620":["\uD83D\uDE20",["angry"]],"1f621":["\uD83D\uDE21",["rage"]],"1f622":["\uD83D\uDE22",["cry"],":'("],"1f623":["\uD83D\uDE23",["persevere"]],"1f624":["\uD83D\uDE24",["triumph"]],"1f625":["\uD83D\uDE25",["disappointed_relieved"]],"1f626":["\uD83D\uDE26",["frowning"]],"1f627":["\uD83D\uDE27",["anguished"]],"1f628":["\uD83D\uDE28",["fearful"]],"1f629":["\uD83D\uDE29",["weary"]],"1f62a":["\uD83D\uDE2A",["sleepy"]],"1f62b":["\uD83D\uDE2B",["tired_face"]],"1f62c":["\uD83D\uDE2C",["grimacing"]],"1f62d":["\uD83D\uDE2D",["sob"],":'("],"1f62e":["\uD83D\uDE2E",["open_mouth"]],"1f62f":["\uD83D\uDE2F",["hushed"]],"1f630":["\uD83D\uDE30",["cold_sweat"]],"1f631":["\uD83D\uDE31",["scream"]],"1f632":["\uD83D\uDE32",["astonished"]],"1f633":["\uD83D\uDE33",["flushed"]],"1f634":["\uD83D\uDE34",["sleeping"]],"1f635":["\uD83D\uDE35",["dizzy_face"]],"1f636":["\uD83D\uDE36",["no_mouth"]],"1f637":["\uD83D\uDE37",["mask"]],"1f638":["\uD83D\uDE38",["smile_cat"]],"1f639":["\uD83D\uDE39",["joy_cat"]],"1f63a":["\uD83D\uDE3A",["smiley_cat"]],"1f63b":["\uD83D\uDE3B",["heart_eyes_cat"]],"1f63c":["\uD83D\uDE3C",["smirk_cat"]],"1f63d":["\uD83D\uDE3D",["kissing_cat"]],"1f63e":["\uD83D\uDE3E",["pouting_cat"]],"1f63f":["\uD83D\uDE3F",["crying_cat_face"]],"1f640":["\uD83D\uDE40",["scream_cat"]],"1f645":["\uD83D\uDE45",["no_good"]],"1f646":["\uD83D\uDE46",["ok_woman"]],"1f647":["\uD83D\uDE47",["bow"]],"1f648":["\uD83D\uDE48",["see_no_evil"]],"1f649":["\uD83D\uDE49",["hear_no_evil"]],"1f64a":["\uD83D\uDE4A",["speak_no_evil"]],"1f64b":["\uD83D\uDE4B",["raising_hand"]],"1f64c":["\uD83D\uDE4C",["raised_hands"]],"1f64d":["\uD83D\uDE4D",["person_frowning"]],"1f64e":["\uD83D\uDE4E",["person_with_pouting_face"]],"1f64f":["\uD83D\uDE4F",["pray"]],"1f680":["\uD83D\uDE80",["rocket"]],"1f681":["\uD83D\uDE81",["helicopter"]],"1f682":["\uD83D\uDE82",["steam_locomotive"]],"1f683":["\uD83D\uDE83",["railway_car","train"]],"1f684":["\uD83D\uDE84",["bullettrain_side"]],"1f685":["\uD83D\uDE85",["bullettrain_front"]],"1f686":["\uD83D\uDE86",["train2"]],"1f687":["\uD83D\uDE87",["metro"]],"1f688":["\uD83D\uDE88",["light_rail"]],"1f689":["\uD83D\uDE89",["station"]],"1f68a":["\uD83D\uDE8A",["tram"]],"1f68c":["\uD83D\uDE8C",["bus"]],"1f68d":["\uD83D\uDE8D",["oncoming_bus"]],"1f68e":["\uD83D\uDE8E",["trolleybus"]],"1f68f":["\uD83D\uDE8F",["busstop"]],"1f690":["\uD83D\uDE90",["minibus"]],"1f691":["\uD83D\uDE91",["ambulance"]],"1f692":["\uD83D\uDE92",["fire_engine"]],"1f693":["\uD83D\uDE93",["police_car"]],"1f694":["\uD83D\uDE94",["oncoming_police_car"]],"1f695":["\uD83D\uDE95",["taxi"]],"1f696":["\uD83D\uDE96",["oncoming_taxi"]],"1f697":["\uD83D\uDE97",["car","red_car"]],"1f698":["\uD83D\uDE98",["oncoming_automobile"]],"1f699":["\uD83D\uDE99",["blue_car"]],"1f69a":["\uD83D\uDE9A",["truck"]],"1f69b":["\uD83D\uDE9B",["articulated_lorry"]],"1f69c":["\uD83D\uDE9C",["tractor"]],"1f69d":["\uD83D\uDE9D",["monorail"]],"1f69e":["\uD83D\uDE9E",["mountain_railway"]],"1f69f":["\uD83D\uDE9F",["suspension_railway"]],"1f6a0":["\uD83D\uDEA0",["mountain_cableway"]],"1f6a1":["\uD83D\uDEA1",["aerial_tramway"]],"1f6a2":["\uD83D\uDEA2",["ship"]],"1f6a3":["\uD83D\uDEA3",["rowboat"]],"1f6a4":["\uD83D\uDEA4",["speedboat"]],"1f6a5":["\uD83D\uDEA5",["traffic_light"]],"1f6a6":["\uD83D\uDEA6",["vertical_traffic_light"]],"1f6a7":["\uD83D\uDEA7",["construction"]],"1f6a8":["\uD83D\uDEA8",["rotating_light"]],"1f6a9":["\uD83D\uDEA9",["triangular_flag_on_post"]],"1f6aa":["\uD83D\uDEAA",["door"]],"1f6ab":["\uD83D\uDEAB",["no_entry_sign"]],"1f6ac":["\uD83D\uDEAC",["smoking"]],"1f6ad":["\uD83D\uDEAD",["no_smoking"]],"1f6ae":["\uD83D\uDEAE",["put_litter_in_its_place"]],"1f6af":["\uD83D\uDEAF",["do_not_litter"]],"1f6b0":["\uD83D\uDEB0",["potable_water"]],"1f6b1":["\uD83D\uDEB1",["non-potable_water"]],"1f6b2":["\uD83D\uDEB2",["bike"]],"1f6b3":["\uD83D\uDEB3",["no_bicycles"]],"1f6b4":["\uD83D\uDEB4",["bicyclist"]],"1f6b5":["\uD83D\uDEB5",["mountain_bicyclist"]],"1f6b6":["\uD83D\uDEB6",["walking"]],"1f6b7":["\uD83D\uDEB7",["no_pedestrians"]],"1f6b8":["\uD83D\uDEB8",["children_crossing"]],"1f6b9":["\uD83D\uDEB9",["mens"]],"1f6ba":["\uD83D\uDEBA",["womens"]],"1f6bb":["\uD83D\uDEBB",["restroom"]],"1f6bc":["\uD83D\uDEBC",["baby_symbol"]],"1f6bd":["\uD83D\uDEBD",["toilet"]],"1f6be":["\uD83D\uDEBE",["wc"]],"1f6bf":["\uD83D\uDEBF",["shower"]],"1f6c0":["\uD83D\uDEC0",["bath"]],"1f6c1":["\uD83D\uDEC1",["bathtub"]],"1f6c2":["\uD83D\uDEC2",["passport_control"]],"1f6c3":["\uD83D\uDEC3",["customs"]],"1f6c4":["\uD83D\uDEC4",["baggage_claim"]],"1f6c5":["\uD83D\uDEC5",["left_luggage"]],"0023":["\u0023\u20E3",["hash"]],"0030":["\u0030\u20E3",["zero"]],"0031":["\u0031\u20E3",["one"]],"0032":["\u0032\u20E3",["two"]],"0033":["\u0033\u20E3",["three"]],"0034":["\u0034\u20E3",["four"]],"0035":["\u0035\u20E3",["five"]],"0036":["\u0036\u20E3",["six"]],"0037":["\u0037\u20E3",["seven"]],"0038":["\u0038\u20E3",["eight"]],"0039":["\u0039\u20E3",["nine"]],"1f1e8-1f1f3":["\uD83C\uDDE8\uD83C\uDDF3",["cn"]],"1f1e9-1f1ea":["\uD83C\uDDE9\uD83C\uDDEA",["de"]],"1f1ea-1f1f8":["\uD83C\uDDEA\uD83C\uDDF8",["es"]],"1f1eb-1f1f7":["\uD83C\uDDEB\uD83C\uDDF7",["fr"]],"1f1ec-1f1e7":["\uD83C\uDDEC\uD83C\uDDE7",["gb","uk"]],"1f1ee-1f1f9":["\uD83C\uDDEE\uD83C\uDDF9",["it"]],"1f1ef-1f1f5":["\uD83C\uDDEF\uD83C\uDDF5",["jp"]],"1f1f0-1f1f7":["\uD83C\uDDF0\uD83C\uDDF7",["kr"]],"1f1f7-1f1fa":["\uD83C\uDDF7\uD83C\uDDFA",["ru"]],"1f1fa-1f1f8":["\uD83C\uDDFA\uD83C\uDDF8",["us"]]} diff --git a/app/js/lib/mtproto.js b/app/js/lib/mtproto.js new file mode 100644 index 00000000..9d58eda6 --- /dev/null +++ b/app/js/lib/mtproto.js @@ -0,0 +1,2612 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +var _logTimer = (new Date()).getTime(); +function dLog () { + try { + var t = '[' + (((new Date()).getTime() - _logTimer) / 1000).toFixed(3) + '] '; + if (window.console && console.log) { + var args = Array.prototype.slice.call(arguments); + args.unshift(t); + console.log.apply(console, args); + } + } catch (e) {} + + return true; +} + +function bigint (num) { + return new BigInteger(num.toString(16), 16); +} + +function dHexDump (bytes) { + var arr = []; + for (var i = 0; i < bytes.length; i++) { + if (i && !(i % 2)) { + if (!(i % 16)) { + arr.push("\n"); + } else if (!(i % 4)) { + arr.push(' '); + } else { + arr.push(' '); + } + } + arr.push((bytes[i] < 16 ? '0' : '') + bytes[i].toString(16)); + } + + console.log(arr.join('')); +} + +function bytesToHex (bytes) { + var arr = []; + for (var i = 0; i < bytes.length; i++) { + arr.push((bytes[i] < 16 ? '0' : '') + bytes[i].toString(16)); + } + return arr.join(''); +} + +function bytesFromHex (hexString) { + var len = hexString.length, + i, + bytes = []; + + for (i = 0; i < len; i += 2) { + bytes.push(parseInt(hexString.substr(i, 2), 16)); + } + + return bytes; +} + +function bytesCmp (bytes1, bytes2) { + var len = bytes1.length; + if (len != bytes2.length) { + return false; + } + + for (var i = 0; i < len; i++) { + if (bytes1[i] != bytes2[i]) { + return false; + } + } + return true; +} + +function bytesXor (bytes1, bytes2) { + var len = bytes1.length, + bytes = []; + + for (var i = 0; i < len; ++i) { + bytes[i] = bytes1[i] ^ bytes2[i]; + } + + return bytes; +} + +function bytesToWords (bytes) { + var len = bytes.length, + words = []; + + for (var i = 0; i < len; i++) { + words[i >>> 2] |= bytes[i] << (24 - (i % 4) * 8); + } + + return new CryptoJS.lib.WordArray.init(words, len); +} + +function bytesFromWords (wordArray) { + var words = wordArray.words, + sigBytes = wordArray.sigBytes, + bytes = []; + + for (var i = 0; i < sigBytes; i++) { + bytes.push((words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff); + } + + return bytes; +} + +function bytesFromBigInt (bigInt, len) { + var bytes = bigInt.toByteArray(); + + while (!bytes[0] && (!len || bytes.length > len)) { + bytes = bytes.slice(1); + } + + return bytes; +} + +function bytesToArrayBuffer (b) { + var len = b.length, + array = new Uint8Array(len); + + for (var i = 0; i < len; ++i) { + array[i] = b[i]; + } + + return array.buffer; +} + +function bytesFromArrayBuffer (buffer) { + var len = buffer.byteLength, + byteView = new Uint8Array(buffer), + bytes = []; + + for (var i = 0; i < len; ++i) { + bytes[i] = byteView[i]; + } + + return bytes; +} + +function longToInts (sLong) { + var divRem = new BigInteger(sLong, 10).divideAndRemainder(bigint(0x100000000)); + + return [divRem[0].intValue(), divRem[1].intValue()]; +} + +function longToBytes (sLong) { + return bytesFromWords({words: longToInts(sLong), sigBytes: 8}).reverse(); +} + +function longFromInts (high, low) { + return bigint(high).shiftLeft(32).add(bigint(low)).toString(10); +} + +function intToUint (val) { + val = parseInt(val); + if (val < 0) { + val = val + 4294967296; + } + return val; +} + +function uintToInt (val) { + if (val > 2147483647) { + val = val - 4294967296; + } + return val; +} + +function sha1Hash (bytes) { + // dLog('SHA-1 hash start'); + var hashBytes = sha1.hash(bytes, true); + // dLog('SHA-1 hash finish'); + + return hashBytes; +} + + + +function rsaEncrypt (publicKey, bytes) { + var needPadding = 255 - bytes.length; + if (needPadding > 0) { + var padding = new Array(needPadding); + (new SecureRandom()).nextBytes(padding); + + bytes = bytes.concat(padding); + } + + // dLog('RSA encrypt start'); + var N = new BigInteger(publicKey.modulus, 16), + E = new BigInteger(publicKey.exponent, 16), + X = new BigInteger(bytes), + encryptedBigInt = X.modPowInt(E, N), + encryptedBytes = bytesFromBigInt(encryptedBigInt, 256); + + // dLog('RSA encrypt finish'); + + return encryptedBytes; +} + +function aesEncrypt (bytes, keyBytes, ivBytes) { + // dLog('AES encrypt start', bytes.length/*, bytesToHex(keyBytes), bytesToHex(ivBytes)*/); + + var needPadding = 16 - (bytes.length % 16); + if (needPadding > 0 && needPadding < 16) { + var padding = new Array(needPadding); + (new SecureRandom()).nextBytes(padding); + + bytes = bytes.concat(padding); + } + + var encryptedWords = CryptoJS.AES.encrypt(bytesToWords(bytes), bytesToWords(keyBytes), { + iv: bytesToWords(ivBytes), + padding: CryptoJS.pad.NoPadding, + mode: CryptoJS.mode.IGE + }).ciphertext; + + var encryptedBytes = bytesFromWords(encryptedWords); + + // dLog('AES encrypt finish'); + + return encryptedBytes; +} + +function aesDecrypt (encryptedBytes, keyBytes, ivBytes) { + dLog('AES decrypt start', encryptedBytes.length/*, bytesToHex(keyBytes), bytesToHex(ivBytes)*/); + + var decryptedWords = CryptoJS.AES.decrypt({ciphertext: bytesToWords(encryptedBytes)}, bytesToWords(keyBytes), { + iv: bytesToWords(ivBytes), + padding: CryptoJS.pad.NoPadding, + mode: CryptoJS.mode.IGE + }); + + var bytes = bytesFromWords(decryptedWords); + + dLog('AES decrypt finish'); + + return bytes; +} + +function gzipUncompress (bytes) { + // dLog('Gzip uncompress start'); + var result = (new Zlib.Gunzip(bytes)).decompress(); + // dLog('Gzip uncompress finish'); + return result; +} + +function nextRandomInt (maxValue) { + return Math.floor(Math.random() * maxValue); +}; + +function pqPrimeFactorization (pqBytes) { + dLog('PQ start'); + + var what = new BigInteger(pqBytes), + g; + + var it = 0; + for (var i = 0; i < 3; i++) { + var q = (nextRandomInt(128) & 15) + 17, + x = bigint(nextRandomInt(1000000000) + 1), + y = x.clone(), + lim = 1 << (i + 18); + + for (var j = 1; j < lim; j++) { + ++it; + var a = x.clone(), + b = x.clone(), + c = bigint(q); + + while (!b.equals(BigInteger.ZERO)) { + if (!b.and(BigInteger.ONE).equals(BigInteger.ZERO)) { + c = c.add(a); + if (c.compareTo(what) > 0) { + c = c.subtract(what); + } + } + a = a.add(a); + if (a.compareTo(what) > 0) { + a = a.subtract(what); + } + b = b.shiftRight(1); + } + + x = c.clone(); + var z = x.compareTo(y) < 0 ? y.subtract(x) : x.subtract(y); + g = z.gcd(what); + if (!g.equals(BigInteger.ONE)) { + break; + } + if ((j & (j - 1)) == 0) { + y = x.clone(); + } + } + if (g.compareTo(BigInteger.ONE) > 0) { + break; + } + } + + var f = what.divide(g), P, Q; + + if (g.compareTo(f) > 0) { + P = f; + Q = g; + } else { + P = g; + Q = f; + } + + dLog('PQ finish', it + ' iterations'); + + return [bytesFromBigInt(P), bytesFromBigInt(Q)]; +} + + +function TLSerialization (options) { + options = options || {}; + this.maxLength = options.startMaxLength || 2048; // 2Kb + this.offset = 0; // in bytes + + this.createBuffer(); + + // this.debug = options.debug !== undefined ? options.debug : true; + this.mtproto = options.mtproto || false; + return this; +} + +TLSerialization.prototype.createBuffer = function () { + this.buffer = new ArrayBuffer(this.maxLength); + this.intView = new Int32Array(this.buffer); + this.byteView = new Uint8Array(this.buffer); +}; + +TLSerialization.prototype.getArray = function () { + var resultBuffer = new ArrayBuffer(this.offset); + var resultArray = new Int32Array(resultBuffer); + + resultArray.set(this.intView.subarray(0, this.offset / 4)); + + return resultArray; +}; + +TLSerialization.prototype.getBuffer = function () { + return this.getArray().buffer; +}; + +TLSerialization.prototype.getBytes = function () { + var bytes = []; + for (var i = 0; i < this.offset; i++) { + bytes.push(this.byteView[i]); + } + return bytes; +}; + +TLSerialization.prototype.checkLength = function (needBytes) { + if (this.offset + needBytes < this.maxLength) { + return; + } + + dLog('Increase buffer', this.offset, needBytes, this.maxLength); + console.trace(); + this.maxLength = Math.max(this.maxLength * 2, this.offset + needBytes + 16); + var previousBuffer = this.buffer, + previousArray = new Int32Array(previousBuffer); + + this.createBuffer(); + + new Int32Array(this.buffer).set(previousArray); +}; + +TLSerialization.prototype.writeInt = function (i, field) { + this.debug && dLog('>>>', i.toString(16), i, field); + + this.checkLength(4); + this.intView[this.offset / 4] = i; + this.offset += 4; +}; + +TLSerialization.prototype.storeInt = function (i, field) { + this.writeInt(i, (field || '') + ':int'); +}; + +TLSerialization.prototype.storeBool = function (i, field) { + if (i) { + this.writeInt(0x997275b5, (field || '') + ':bool'); + } else { + this.writeInt(0xbc799737, (field || '') + ':bool'); + } +}; + +TLSerialization.prototype.storeLongP = function (iHigh, iLow, field) { + this.writeInt(iLow, (field || '') + ':long[low]'); + this.writeInt(iHigh, (field || '') + ':long[high]'); +}; + +TLSerialization.prototype.storeLong = function (sLong, field) { + if (angular.isArray(sLong)) { + if (sLong.length == 2) { + return this.storeLongP(sLong[0], sLong[1], field); + } else { + return this.storeIntBytes(sLong, 64, field); + } + } + + var divRem = new BigInteger(sLong, 10).divideAndRemainder(bigint(0x100000000)); + + this.writeInt(intToUint(divRem[1].intValue()), (field || '') + ':long[low]'); + this.writeInt(intToUint(divRem[0].intValue()), (field || '') + ':long[high]'); +}; + +TLSerialization.prototype.storeDouble = function (f) { + var buffer = new ArrayBuffer(8); + var intView = new Int32Array(buffer); + var doubleView = new Float64Array(buffer); + + doubleView[0] = f; + + this.writeInt(intView[0], (field || '') + ':double[low]'); + this.writeInt(intView[1], (field || '') + ':double[high]'); +}; + +TLSerialization.prototype.storeString = function (s, field) { + this.debug && dLog('>>>', s, (field || '') + ':string'); + + var sUTF8 = unescape(encodeURIComponent(s)); + + this.checkLength(sUTF8.length + 8); + + + var len = sUTF8.length; + if (len <= 253) { + this.byteView[this.offset++] = len; + } else { + this.byteView[this.offset++] = 254; + this.byteView[this.offset++] = len & 0xFF; + this.byteView[this.offset++] = (len & 0xFF00) >> 8; + this.byteView[this.offset++] = (len & 0xFF0000) >> 16; + } + for (var i = 0; i < len; i++) { + this.byteView[this.offset++] = sUTF8.charCodeAt(i); + } + + // Padding + while (this.offset % 4) { + this.byteView[this.offset++] = 0; + } +} + + +TLSerialization.prototype.storeBytes = function (bytes, field) { + this.debug && dLog('>>>', bytesToHex(bytes), (field || '') + ':bytes'); + + this.checkLength(bytes.length + 8); + + var len = bytes.length; + if (len <= 253) { + this.byteView[this.offset++] = len; + } else { + this.byteView[this.offset++] = 254; + this.byteView[this.offset++] = len & 0xFF; + this.byteView[this.offset++] = (len & 0xFF00) >> 8; + this.byteView[this.offset++] = (len & 0xFF0000) >> 16; + } + for (var i = 0; i < len; i++) { + this.byteView[this.offset++] = bytes[i]; + } + + // Padding + while (this.offset % 4) { + this.byteView[this.offset++] = 0; + } +} + +TLSerialization.prototype.storeIntBytes = function (bytes, bits, field) { + var len = bytes.length; + if ((bits % 32) || (len * 8) != bits) { + throw new Error('Invalid bits: ' + bits + ', ' + bytes.length); + } + + this.debug && dLog('>>>', bytesToHex(bytes), (field || '') + ':int' + bits); + this.checkLength(len); + + for (var i = 0; i < len; i++) { + this.byteView[this.offset++] = bytes[i]; + } +}; + +TLSerialization.prototype.storeRawBytes = function (bytes, field) { + var len = bytes.length; + + this.debug && dLog('>>>', bytesToHex(bytes), (field || '')); + this.checkLength(len); + + for (var i = 0; i < len; i++) { + this.byteView[this.offset++] = bytes[i]; + } +}; + + +TLSerialization.prototype.storeMethod = function (methodName, params) { + var schema = this.mtproto ? Config.Schema.MTProto : Config.Schema.API, + methodData = false, + i; + + for (i = 0; i < schema.methods.length; i++) { + if (schema.methods[i].method == methodName) { + methodData = schema.methods[i]; + break + } + } + if (!methodData) { + throw new Error('No method ' + methodName + ' found'); + } + + this.storeInt(intToUint(methodData.id), methodName + '[id]'); + + var self = this; + angular.forEach(methodData.params, function (param) { + self.storeObject(params[param.name], param.type, methodName + '[' + param.name + ']'); + }); +}; + +TLSerialization.prototype.storeObject = function (obj, type, field) { + switch (type) { + case 'int': return this.storeInt(obj, field); + case 'long': return this.storeLong(obj, field); + case 'int128': return this.storeIntBytes(obj, 128, field); + case 'int256': return this.storeIntBytes(obj, 256, field); + case 'int512': return this.storeIntBytes(obj, 512, field); + case 'string': return this.storeString(obj, field); + case 'bytes': return this.storeBytes(obj, field); + case 'double': return this.storeDouble(obj, field); + case 'Bool': return this.storeBool(obj, field); + } + + if (angular.isArray(obj)) { + if (type.substr(0, 6) == 'Vector') { + this.writeInt(0x1cb5c415, field + '[id]'); + } + else if (type.substr(0, 6) != 'vector') { + throw new Error('Invalid vector type ' + type); + } + var itemType = type.substr(7, type.length - 8); // for "Vector" + this.writeInt(obj.length, field + '[count]'); + for (var i = 0; i < obj.length; i++) { + this.storeObject(obj[i], itemType, field + '[' + i + ']'); + } + return true; + } + else if (type.substr(0, 6).toLowerCase() == 'vector') { + throw new Error('Invalid vector object'); + } + + if (!angular.isObject(obj)) { + throw new Error('Invalid object for type ' + type); + } + + var schema = this.mtproto ? Config.Schema.MTProto : Config.Schema.API, + predicate = obj['_'], + isBare = false, + constructorData = false, + i; + + if (isBare = (type.charAt(0) == '%')) { + type = type.substr(1); + } + + for (i = 0; i < schema.constructors.length; i++) { + if (schema.constructors[i].predicate == predicate) { + constructorData = schema.constructors[i]; + break + } + } + if (!constructorData) { + throw new Error('No predicate ' + predicate + ' found'); + } + + if (predicate == type) { + isBare = true; + } + + if (!isBare) { + this.writeInt(intToUint(constructorData.id), field + '[' + predicate + '][id]'); + } + + var self = this; + angular.forEach(constructorData.params, function (param) { + self.storeObject(obj[param.name], param.type, field + '[' + predicate + '][' + param.name + ']'); + }); +}; + + + +function TLDeserialization (buffer, options) { + options = options || {}; + + this.offset = 0; // in bytes + + this.buffer = buffer; + this.intView = new Uint32Array(this.buffer); + this.byteView = new Uint8Array(this.buffer); + + // this.debug = options.debug !== undefined ? options.debug : true; + this.mtproto = options.mtproto || false; + return this; +} + +TLDeserialization.prototype.readInt = function (field) { + if (this.offset >= this.intView.length * 4) { + throw new Error('Nothing to fetch'); + } + + var i = this.intView[this.offset / 4]; + + this.debug && dLog('<<<', i.toString(16), i, field); + + this.offset += 4; + + return i; +}; + +TLDeserialization.prototype.fetchInt = function (field) { + return this.readInt((field || '') + ':int'); +} + +TLDeserialization.prototype.fetchDouble = function (field) { + var buffer = new ArrayBuffer(8); + var intView = new Int32Array(buffer); + var doubleView = new Float64Array(buffer); + + intView[0] = this.readInt((field || '') + ':double[low]'), + intView[1] = this.readInt((field || '') + ':double[high]'); + + return doubleView[0]; +}; + +TLDeserialization.prototype.fetchLong = function (field) { + var iLow = this.readInt((field || '') + ':long[low]'), + iHigh = this.readInt((field || '') + ':long[high]'); + + var longDec = bigint(iHigh).shiftLeft(32).add(bigint(iLow)).toString(); + + return longDec; +} + +TLDeserialization.prototype.fetchBool = function (field) { + var i = this.readInt((field || '') + ':bool'); + if (i == 0x997275b5) { + return true; + } else if (i == 0xbc799737) { + return false + } + throw new Error('Unknown Bool constructor ' + i); +} + +TLDeserialization.prototype.fetchString = function (field) { + var len = this.byteView[this.offset++]; + + if (len == 254) { + var len = this.byteView[this.offset++] | + (this.byteView[this.offset++] << 8) | + (this.byteView[this.offset++] << 16); + } + + var sUTF8 = ''; + for (var i = 0; i < len; i++) { + sUTF8 += String.fromCharCode(this.byteView[this.offset++]); + } + + // Padding + while (this.offset % 4) { + this.offset++; + } + + try { + var s = decodeURIComponent(escape(sUTF8)); + } catch (e) { + var s = sUTF8; + } + + this.debug && dLog('<<<', s, (field || '') + ':string'); + + return s; +} + + +TLDeserialization.prototype.fetchBytes = function (field) { + var len = this.byteView[this.offset++]; + + if (len == 254) { + var len = this.byteView[this.offset++] | + (this.byteView[this.offset++] << 8) | + (this.byteView[this.offset++] << 16); + } + + var bytes = []; + for (var i = 0; i < len; i++) { + bytes.push(this.byteView[this.offset++]); + } + + // Padding + while (this.offset % 4) { + this.offset++; + } + + this.debug && dLog('<<<', bytesToHex(bytes), (field || '') + ':bytes'); + + return bytes; +} + +TLDeserialization.prototype.fetchIntBytes = function (bits, field) { + if (bits % 32) { + throw new Error('Invalid bits: ' + bits); + } + + var len = bits / 8; + var bytes = []; + for (var i = 0; i < len; i++) { + bytes.push(this.byteView[this.offset++]); + } + + this.debug && dLog('<<<', bytesToHex(bytes), (field || '') + ':int' + bits); + + return bytes; +}; + + +TLDeserialization.prototype.fetchRawBytes = function (len, field) { + if (len === false) { + len = this.readInt((field || '') + '_length'); + } + + var bytes = []; + for (var i = 0; i < len; i++) { + bytes.push(this.byteView[this.offset++]); + } + + this.debug && dLog('<<<', bytesToHex(bytes), (field || '')); + + return bytes; +}; + +TLDeserialization.prototype.fetchObject = function (type, field) { + switch (type) { + case 'int': return this.fetchInt(field); + case 'long': return this.fetchLong(field); + case 'int128': return this.fetchIntBytes(128, field); + case 'int256': return this.fetchIntBytes(256, field); + case 'int512': return this.fetchIntBytes(512, field); + case 'string': return this.fetchString(field); + case 'bytes': return this.fetchBytes(field); + case 'double': return this.fetchDouble(field); + case 'Bool': return this.fetchBool(field); + } + + field = field || type || 'Object'; + + if (type.substr(0, 6) == 'Vector' || type.substr(0, 6) == 'vector') { + if (type.charAt(0) == 'V') { + var constructor = this.readInt(field + '[id]'); + if (constructor != 0x1cb5c415) { + throw new Error('Invalid vector constructor ' + constructor); + } + } + var len = this.readInt(field + '[count]'); + var result = []; + if (len > 0) { + var itemType = type.substr(7, type.length - 8); // for "Vector" + for (var i = 0; i < len; i++) { + result.push(this.fetchObject(itemType, field + '[' + i + ']')) + } + } + + return result; + } + + var schema = this.mtproto ? Config.Schema.MTProto : Config.Schema.API, + predicate = false, + constructorData = false; + + if (type.charAt(0) == '%') { + var checkType = type.substr(1); + for (i = 0; i < schema.constructors.length; i++) { + if (schema.constructors[i].type == checkType) { + constructorData = schema.constructors[i]; + break + } + } + if (!constructorData) { + throw new Error('Constructor not found for type: ' + type); + } + } + else if (type.charAt(0) >= 97 && type.charAt(0) <= 122) { + for (i = 0; i < schema.constructors.length; i++) { + if (schema.constructors[i].predicate == type) { + constructorData = schema.constructors[i]; + break + } + } + if (!constructorData) { + throw new Error('Constructor not found for predicate: ' + type); + } + } + else { + var constructor = this.readInt(field + '[id]'), + constructorCmp = uintToInt(constructor); + + if (constructorCmp == 0x3072cfa1) { // Gzip packed + var compressed = this.fetchBytes(field + '[packed_string]'), + uncompressed = gzipUncompress(compressed), + buffer = bytesToArrayBuffer(uncompressed), + newDeserializer = (new TLDeserialization(buffer)); + + return newDeserializer.fetchObject(type, field); + } + + for (i = 0; i < schema.constructors.length; i++) { + if (schema.constructors[i].id == constructorCmp) { + constructorData = schema.constructors[i]; + break; + } + } + + var fallback = false; + if (!constructorData && this.mtproto) { + var schemaFallback = Config.Schema.API; + for (i = 0; i < schemaFallback.constructors.length; i++) { + if (schemaFallback.constructors[i].id == constructorCmp) { + constructorData = schemaFallback.constructors[i]; + + delete this.mtproto; + fallback = true; + break; + } + } + } + if (!constructorData) { + throw new Error('Constructor not found: ' + constructor); + } + } + + predicate = constructorData.predicate; + + var result = {'_': predicate}; + + var self = this; + angular.forEach(constructorData.params, function (param) { + result[param.name] = self.fetchObject(param.type, field + '[' + predicate + '][' + param.name + ']'); + }); + + if (fallback) { + this.mtproto = true; + } + + return result; +}; + +TLDeserialization.prototype.getOffset = function () { + return this.offset; +}; + +TLDeserialization.prototype.fetchEnd = function () { + if (this.offset != this.byteView.length) { + throw new Error('Fetch end with non-empty buffer'); + } + return true; +}; + +if (typeof angular != 'undefined') angular.module('mtproto.services', ['myApp.services']). + +factory('MtpDcConfigurator', function () { + var dcOptions = window._testMode + ? [ + {id: 1, host: '173.240.5.253', port: 80}, + {id: 2, host: '95.142.192.65', port: 80}, + {id: 3, host: '174.140.142.5', port: 80} + ] + : [ + {id: 1, host: '173.240.5.1', port: 80}, + {id: 2, host: '95.142.192.66', port: 80}, + {id: 3, host: '174.140.142.6', port: 80}, + {id: 4, host: '31.210.235.12', port: 80}, + {id: 5, host: '116.51.22.2', port: 80}, + ]; + + var chosenServers = {}; + + function chooseServer(dcID) { + if (chosenServers[dcID] === undefined) { + var chosenServer = false, + i, dcOption; + for (i = 0; i < dcOptions.length; i++) { + dcOption = dcOptions[i]; + if (dcOption.id == dcID) { + chosenServer = dcOption.host + ':' + dcOption.port; + } + } + chosenServers[dcID] = chosenServer; + } + + return chosenServers[dcID]; + } + + return { + chooseServer: chooseServer + }; +}). + +factory('MtpRsaKeysManager', function () { + +/** +* Server public key, obtained from here: https://core.telegram.org/api/obtaining_api_id +* +* -----BEGIN RSA PUBLIC KEY----- +* MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6 +* lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS +* an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw +* Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+ +* 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n +* Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB +* -----END RSA PUBLIC KEY----- +*/ + + var publisKeysHex = [{ + modulus: 'c150023e2f70db7985ded064759cfecf0af328e69a41daf4d6f01b538135a6f91f8f8b2a0ec9ba9720ce352efcf6c5680ffc424bd634864902de0b4bd6d49f4e580230e3ae97d95c8b19442b3c0a10d8f5633fecedd6926a7f6dab0ddb7d457f9ea81b8465fcd6fffeed114011df91c059caedaf97625f6c96ecc74725556934ef781d866b34f011fce4d835a090196e9a5f0e4449af7eb697ddb9076494ca5f81104a305b6dd27665722c46b60e5df680fb16b210607ef217652e60236c255f6a28315f4083a96791d7214bf64c1df4fd0db1944fb26a2a57031b32eee64ad15a8ba68885cde74a5bfc920f6abf59ba5c75506373e7130f9042da922179251f', + exponent: '010001' + }]; + + var publicKeysParsed = {}; + var prepared = false; + + function prepareRsaKeys () { + if (prepared) { + return; + } + + for (var i = 0; i < publisKeysHex.length; i++) { + var keyParsed = publisKeysHex[i]; + + var RSAPublicKey = new TLSerialization(); + RSAPublicKey.storeBytes(bytesFromHex(keyParsed.modulus), 'n'); + RSAPublicKey.storeBytes(bytesFromHex(keyParsed.exponent), 'e'); + + var buffer = RSAPublicKey.getBuffer(); + + var fingerprintBytes = sha1Hash(buffer).slice(-8); + fingerprintBytes.reverse(); + + var fingerprint = new BigInteger(fingerprintBytes).toString(16); + + publicKeysParsed[fingerprint] = { + modulus: keyParsed.modulus, + exponent: keyParsed.exponent + }; + } + + prepared = true; + }; + + function selectRsaKeyByFingerPrint (fingerprints) { + prepareRsaKeys(); + + var fingerprintHex, foundKey, i; + for (i = 0; i < fingerprints.length; i++) { + fingerprintHex = new BigInteger(fingerprints[i], 10).toString(16); + if (foundKey = publicKeysParsed[fingerprintHex]) { + return angular.extend({fingerprint: fingerprints[i]}, foundKey); + } + } + + return false; + }; + + return { + prepare: prepareRsaKeys, + select: selectRsaKeyByFingerPrint + }; +}). + +service('MtpSecureRandom', SecureRandom). + +factory('MtpMessageIdGenerator', function (AppConfigManager) { + var lastMessageID = [0, 0], + timeOffset = 0; + + AppConfigManager.get('server_time_offset').then(function (to) { + if (to) { + timeOffset = to; + } + }); + + function generateMessageID () { + var timeTicks = +new Date() + timeOffset, + timeSec = Math.floor(timeTicks / 1000), + timeMSec = timeTicks % 1000, + random = nextRandomInt(0xFFFF); + + var messageID = [timeSec, (timeMSec << 21) | (random << 3) | 4]; + if (lastMessageID[0] > messageID[0] || + lastMessageID[0] == messageID[0] && lastMessageID[1] >= messageID[1]) { + + messageID = [lastMessageID[0], lastMessageID[1] + 4]; + } + + lastMessageID = messageID; + + // dLog('generated msg id', messageID); + + return longFromInts(messageID[0], messageID[1]); + }; + + function applyServerTime (serverTime, localTime) { + timeOffset = serverTime - Math.floor((localTime || +new Date()) / 1000); + AppConfigManager.set({server_time_offset: timeOffset}); + }; + + return { + generateID: generateMessageID, + applyServerTime: applyServerTime + }; +}). + +factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpMessageIdGenerator, $http, $q, $timeout) { + + function mtpSendPlainRequest (dcID, requestBuffer) { + var requestLength = requestBuffer.byteLength, + requestArray = new Int32Array(requestBuffer); + + var header = new TLSerialization(); + header.storeLongP(0, 0, 'auth_key_id'); // Auth key + header.storeLong(MtpMessageIdGenerator.generateID(), 'msg_id'); // Msg_id + header.storeInt(requestLength, 'request_length'); + + var headerBuffer = header.getBuffer(), + headerArray = new Int32Array(headerBuffer), + headerLength = headerBuffer.byteLength; + + var resultBuffer = new ArrayBuffer(headerLength + requestLength), + resultArray = new Int32Array(resultBuffer); + + resultArray.set(headerArray); + resultArray.set(requestArray, headerArray.length); + + delete $http.defaults.headers.post['Content-Type']; + delete $http.defaults.headers.common['Accept']; + + return $http.post('http://' + MtpDcConfigurator.chooseServer(dcID) + '/apiw1', resultArray, { + responseType: 'arraybuffer', + transformRequest: null, + transformResponse: function (responseBuffer) { + var deserializer = new TLDeserialization(responseBuffer, {mtproto: true}); + + var auth_key_id = deserializer.fetchLong('auth_key_id'); + var msg_id = deserializer.fetchLong('msg_id'); + var msg_len = deserializer.fetchInt('msg_len'); + + rng_seed_time(); + + return deserializer; + } + }); + }; + + function mtpSendReqPQ (auth) { + var deferred = auth.deferred; + + var request = new TLSerialization({mtproto: true}); + + request.storeMethod('req_pq', {nonce: auth.nonce}); + + mtpSendPlainRequest(auth.dcID, request.getBuffer()).then(function (result) { + var deserializer = result.data; + var response = deserializer.fetchObject('ResPQ'); + + if (response._ != 'resPQ') { + throw new Error('resPQ response invalid: ' + response._); + } + + if (!bytesCmp (auth.nonce, response.nonce)) { + throw new Error('resPQ nonce mismatch'); + } + + auth.serverNonce = response.server_nonce; + auth.pq = response.pq; + auth.fingerprints = response.server_public_key_fingerprints; + + dLog('ResPQ', bytesToHex(auth.serverNonce), bytesToHex(auth.pq), auth.fingerprints); + + auth.publicKey = MtpRsaKeysManager.select(auth.fingerprints); + + if (!auth.publicKey) { + throw new Error('No public key found'); + } + + if (!!window.Worker) { + var worker = new Worker('js/lib/pq_worker.js'); + + worker.onmessage = function (e) { + auth.p = e.data[0]; + auth.q = e.data[1]; + mtpSendReqDhParams(auth); + }; + worker.onerror = function(error) { + dLog('Worker error', error); + deferred.reject(error); + }; + worker.postMessage(auth.pq) + } else { + var pAndQ = pqPrimeFactorization(auth.pq); + auth.p = pAndQ[0]; + auth.q = pAndQ[1]; + + mtpSendReqDhParams(auth); + } + }, function (error) { + deferred.reject(error); + }); + + $timeout(function () { + MtpRsaKeysManager.prepare(); + }); + }; + + function mtpSendReqDhParams (auth) { + var deferred = auth.deferred; + + auth.newNonce = new Array(32); + MtpSecureRandom.nextBytes(auth.newNonce); + + var data = new TLSerialization({mtproto: true}); + data.storeObject({ + _: 'p_q_inner_data', + pq: auth.pq, + p: auth.p, + q: auth.q, + nonce: auth.nonce, + server_nonce: auth.serverNonce, + new_nonce: auth.newNonce + }, 'P_Q_inner_data', 'DECRYPTED_DATA'); + + var dataWithHash = sha1Hash(data.getBuffer()).concat(data.getBytes()); + + var request = new TLSerialization({mtproto: true}); + request.storeMethod('req_DH_params', { + nonce: auth.nonce, + server_nonce: auth.serverNonce, + p: auth.p, + q: auth.q, + public_key_fingerprint: auth.publicKey.fingerprint, + encrypted_data: rsaEncrypt(auth.publicKey, dataWithHash) + }); + + mtpSendPlainRequest(auth.dcID, request.getBuffer()).then(function (result) { + var deserializer = result.data; + var response = deserializer.fetchObject('Server_DH_Params', 'RESPONSE'); + + if (response._ != 'server_DH_params_fail' && response._ != 'server_DH_params_ok') { + deferred.reject(new Error('Server_DH_Params response invalid: ' + response._)); + return false; + } + + if (!bytesCmp (auth.nonce, response.nonce)) { + deferred.reject(new Error('Server_DH_Params nonce mismatch')); + return false; + } + + if (!bytesCmp (auth.serverNonce, response.server_nonce)) { + deferred.reject(new Error('Server_DH_Params server_nonce mismatch')); + return false; + } + + if (response._ == 'server_DH_params_fail') { + var newNonceHash = sha1Hash(auth.newNonce).slice(-16) + if (!bytesCmp (newNonceHash, response.new_nonce_hash)) { + deferred.reject(new Error('server_DH_params_fail new_nonce_hash mismatch')); + return false; + } + deferred.reject(new Error('server_DH_params_fail')); + return false; + } + + try { + mtpDecryptServerDhDataAnswer(auth, response.encrypted_answer); + } catch (e) { + deferred.reject(e); + return false; + } + + mtpSendSetClientDhParams(auth); + }, function (error) { + deferred.reject(error); + }); + }; + + function mtpDecryptServerDhDataAnswer (auth, encryptedAnswer) { + auth.localTime = +new Date(); + + auth.tmpAesKey = sha1Hash(auth.newNonce.concat(auth.serverNonce)).concat(sha1Hash(auth.serverNonce.concat(auth.newNonce)).slice(0, 12)); + auth.tmpAesIv = sha1Hash(auth.serverNonce.concat(auth.newNonce)).slice(12).concat(sha1Hash([].concat(auth.newNonce, auth.newNonce)), auth.newNonce.slice(0, 4)); + + var answerWithHash = aesDecrypt(encryptedAnswer, auth.tmpAesKey, auth.tmpAesIv); + + var hash = answerWithHash.slice(0, 20); + var answerWithPadding = answerWithHash.slice(20); + var buffer = bytesToArrayBuffer(answerWithPadding); + + var deserializer = new TLDeserialization(buffer, {mtproto: true}); + var response = deserializer.fetchObject('Server_DH_inner_data'); + + if (response._ != 'server_DH_inner_data') { + throw new Error('server_DH_inner_data response invalid: ' + constructor); + } + + if (!bytesCmp (auth.nonce, response.nonce)) { + throw new Error('server_DH_inner_data nonce mismatch'); + } + + if (!bytesCmp (auth.serverNonce, response.server_nonce)) { + throw new Error('server_DH_inner_data serverNonce mismatch'); + } + + auth.g = response.g; + auth.dhPrime = response.dh_prime; + auth.gA = response.g_a; + auth.serverTime = response.server_time; + auth.retry = 0; + + var offset = deserializer.getOffset(); + + if (!bytesCmp(hash, sha1Hash(answerWithPadding.slice(0, offset)))) { + throw new Error('server_DH_inner_data SHA1-hash mismatch'); + } + + MtpMessageIdGenerator.applyServerTime(auth.serverTime, auth.localTime); + }; + + function mtpSendSetClientDhParams(auth) { + var deferred = auth.deferred; + + auth.b = new Array(256); + MtpSecureRandom.nextBytes(auth.b); + + var bBigInt = new BigInteger(auth.b); + var dhPrimeBigInt = new BigInteger(auth.dhPrime); + + var gB = bytesFromBigInt(bigint(auth.g).modPow(bBigInt, dhPrimeBigInt)); + + var data = new TLSerialization({mtproto: true}); + data.storeObject({ + _: 'client_DH_inner_data', + nonce: auth.nonce, + server_nonce: auth.serverNonce, + retry_id: [0, auth.retry++], + g_b: gB, + }, 'Client_DH_Inner_Data'); + + var dataWithHash = sha1Hash(data.getBuffer()).concat(data.getBytes()); + + var encryptedData = aesEncrypt(dataWithHash, auth.tmpAesKey, auth.tmpAesIv); + + var request = new TLSerialization({mtproto: true}); + request.storeMethod('set_client_DH_params', { + nonce: auth.nonce, + server_nonce: auth.serverNonce, + encrypted_data: encryptedData + }); + + mtpSendPlainRequest(auth.dcID, request.getBuffer()).then(function (result) { + var deserializer = result.data; + var response = deserializer.fetchObject('Set_client_DH_params_answer'); + + if (response._ != 'dh_gen_ok' && response._ != 'dh_gen_retry' && response._ != 'dh_gen_fail') { + deferred.reject(new Error('Set_client_DH_params_answer response invalid: ' + response._)); + return false; + } + + if (!bytesCmp (auth.nonce, response.nonce)) { + deferred.reject(new Error('Set_client_DH_params_answer nonce mismatch')); + return false + } + + if (!bytesCmp (auth.serverNonce, response.server_nonce)) { + deferred.reject(new Error('Set_client_DH_params_answer server_nonce mismatch')); + return false; + } + + var bBigInt = new BigInteger(auth.b); + var dhPrimeBigInt = new BigInteger(auth.dhPrime); + + var authKey = bytesFromBigInt((new BigInteger(auth.gA)).modPow(bBigInt, dhPrimeBigInt)), + authKeyHash = sha1Hash(authKey), + authKeyAux = authKeyHash.slice(0, 8), + authKeyID = authKeyHash.slice(-8); + + switch (response._) { + case 'dh_gen_ok': + var newNonceHash1 = sha1Hash(auth.newNonce.concat([1], authKeyAux)).slice(-16); + + if (!bytesCmp(newNonceHash1, response.new_nonce_hash1)) { + deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash1 mismatch')); + return false; + } + + var serverSalt = bytesXor(auth.newNonce.slice(0, 8), auth.serverNonce.slice(0, 8)); + dLog('Auth successfull!', authKeyID, authKey, serverSalt); + + auth.authKeyID = authKeyID; + auth.authKey = authKey; + auth.serverSalt = serverSalt; + + deferred.resolve(auth); + break; + + case 'dh_gen_retry': + var newNonceHash2 = sha1Hash(auth.newNonce.concat([2], authKeyAux)).slice(-16); + if (!bytesCmp(newNonceHash2, response.new_nonce_hash2)) { + deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash2 mismatch')); + return false; + } + + return mtpSendSetClientDhParams(auth); + + case 'dh_gen_fail': + var newNonceHash3 = sha1Hash(auth.newNonce.concat([3], authKeyAux)).slice(-16); + if (!bytesCmp(newNonceHash3, response.new_nonce_hash3)) { + deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash3 mismatch')); + return false; + } + + deferred.reject(new Error('Set_client_DH_params_answer fail')); + return false; + } + + }, function (error) { + deferred.reject(error); + }); + }; + + var cached = {}; + + function mtpAuth (dcID) { + if (cached[dcID] !== undefined) { + return cached[dcID]; + } + + var nonce = []; + for (var i = 0; i < 16; i++) { + nonce.push(nextRandomInt(0xFF)); + } + + if (!MtpDcConfigurator.chooseServer(dcID)) { + return $q.reject(new Error('No server found for dc ' + dcID)); + } + + var auth = { + dcID: dcID, + nonce: nonce, + deferred: $q.defer() + }; + + $timeout(function () { + mtpSendReqPQ(auth); + }); + + return cached[dcID] = auth.deferred.promise; + }; + + return { + auth: mtpAuth + }; + +}). + +factory('MtpAesService', function ($q) { + if (!window.Worker/* || true*/) { + return { + encrypt: function (bytes, keyBytes, ivBytes) { + return $q.when(aesEncrypt(bytes, keyBytes, ivBytes)); + }, + decrypt: function (encryptedBytes, keyBytes, ivBytes) { + return $q.when(aesDecrypt(encryptedBytes, keyBytes, ivBytes)); + } + }; + } + + var worker = new Worker('js/lib/aes_worker.js'), + taskID = 0, + awaiting = {}; + + worker.onmessage = function (e) { + var deferred = awaiting[e.data.taskID]; + if (deferred !== undefined) { + deferred.resolve(e.data.result); + delete awaiting[e.data.taskID]; + } + // dLog('AES worker message', e.data, deferred); + }; + worker.onerror = function(error) { + dLog('AES Worker error', error); + }; + + return { + encrypt: function (bytes, keyBytes, ivBytes) { + var deferred = $q.defer(); + + awaiting[taskID] = deferred; + + // dLog('AES post message', {taskID: taskID, task: 'encrypt', bytes: bytes, keyBytes: keyBytes, ivBytes: ivBytes}) + worker.postMessage({taskID: taskID, task: 'encrypt', bytes: bytes, keyBytes: keyBytes, ivBytes: ivBytes}); + + taskID++ + + return deferred.promise; + }, + decrypt: function (encryptedBytes, keyBytes, ivBytes) { + var deferred = $q.defer(); + + awaiting[taskID] = deferred; + worker.postMessage({taskID: taskID, task: 'decrypt', encryptedBytes: encryptedBytes, keyBytes: keyBytes, ivBytes: ivBytes}); + + taskID++; + + return deferred.promise; + } + } +}). + + +factory('MtpSha1Service', function ($q) { + if (!window.Worker/* || true*/) { + return { + hash: function (bytes) { + return $q.when(sha1Hash(bytes)); + } + }; + } + + var worker = new Worker('js/lib/sha1_worker.js'), + taskID = 0, + awaiting = {}; + + worker.onmessage = function (e) { + var deferred = awaiting[e.data.taskID]; + if (deferred !== undefined) { + deferred.resolve(e.data.result); + delete awaiting[e.data.taskID]; + } + // dLog('sha1 got message', e.data, deferred); + }; + worker.onerror = function(error) { + dLog('SHA-1 Worker error', error); + }; + + return { + hash: function (bytes) { + var deferred = $q.defer(); + + awaiting[taskID] = deferred; + // dLog(11, taskID, bytes); + worker.postMessage({taskID: taskID, bytes: bytes}); + + taskID++; + + return deferred.promise; + } + } +}). + +factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerator, MtpSecureRandom, MtpSha1Service, MtpAesService, AppConfigManager, $http, $q, $timeout) { + + var updatesProcessor; + + function MtpNetworker(dcID, authKey, serverSalt) { + this.dcID = dcID; + + this.authKey = authKey; + this.authKeyID = sha1Hash(authKey).slice(-8); + + this.serverSalt = serverSalt; + + this.sessionID = new Array(8); + MtpSecureRandom.nextBytes(this.sessionID); + + if (true) { + this.sessionID[0] = 0xA; + this.sessionID[1] = 0xB; + this.sessionID[3] = 0xC; + this.sessionID[4] = 0xD; + } + + this.seqNo = 0; + this.currentRequests = 0; + + this.sentMessages = {}; + this.serverMessages = []; + this.clientMessages = []; + + this.pendingMessages = {}; + this.pendingAcks = []; + this.pendingResends = []; + this.connectionInited = false; + + this.pendingTimeouts = []; + + this.longPollInt = setInterval(this.checkLongPoll.bind(this), 10000); + this.checkLongPoll(); + }; + + + MtpNetworker.prototype.generateSeqNo = function (notContentRelated) { + var seqNo = this.seqNo * 2; + + if (!notContentRelated) { + seqNo++; + this.seqNo++; + } + + return seqNo; + } + + MtpNetworker.prototype.wrapMtpCall = function (method, params, options) { + var serializer = new TLSerialization({mtproto: true}); + + serializer.storeMethod(method, params); + + var messageID = MtpMessageIdGenerator.generateID(), + seqNo = this.generateSeqNo(), + message = { + msg_id: messageID, + seq_no: seqNo, + body: serializer.getBytes() + }; + + // dLog('MT call', method, params, messageID, seqNo); + + return this.pushMessage(message, options); + }; + + MtpNetworker.prototype.wrapMtpMessage = function (object, options) { + options = options || {}; + + var serializer = new TLSerialization({mtproto: true}); + serializer.storeObject(object, 'Object'); + + var messageID = MtpMessageIdGenerator.generateID(), + seqNo = this.generateSeqNo(options.notContentRelated), + message = { + msg_id: messageID, + seq_no: seqNo, + body: serializer.getBytes() + }; + + // dLog('MT message', object, messageID, seqNo); + + return this.pushMessage(message, options); + }; + + MtpNetworker.prototype.wrapApiCall = function (method, params, options) { + var serializer = new TLSerialization(options); + + if (!this.connectionInited) { + serializer.storeInt(962726977, 'InokeWithLayer10'); + serializer.storeInt(0x69796de9, 'initConnection'); + serializer.storeInt(777, 'api_id'); + serializer.storeString(navigator.userAgent, 'device_model'); + serializer.storeString(navigator.platform, 'system_version'); + serializer.storeString('0.1', 'app_version'); + serializer.storeString(navigator.language, 'lang_code'); + } + + serializer.storeMethod(method, params); + + var messageID = MtpMessageIdGenerator.generateID(), + seqNo = this.generateSeqNo(), + message = { + msg_id: messageID, + seq_no: seqNo, + body: serializer.getBytes(), + isAPI: true + }; + + dLog('Api call', method, messageID, seqNo); + // dLog('Api call', method, params, messageID, seqNo); + + return this.pushMessage(message, options); + }; + + MtpNetworker.prototype.checkLongPoll = function(force) { + // dLog('Check lp', this.longPollPending, (new Date().getTime())); + if (this.longPollPending && (new Date().getTime()) < this.longPollPending) { + return false; + } + this.sendLongPoll(); + }; + + MtpNetworker.prototype.sendLongPoll = function() { + var maxWait = 25000; + this.longPollPending = (new Date().getTime()) + maxWait; + // dLog('Set lp', this.longPollPending, (new Date().getTime())); + + this.wrapMtpCall('http_wait', {max_delay: 0, wait_after: 0, max_wait: maxWait}, {noResponse: true}). + then((function () { + delete this.longPollPending; + setTimeout(this.checkLongPoll.bind(this), 0); + }).bind(this)); + }; + + MtpNetworker.prototype.pushMessage = function(message, options) { + var deferred = $q.defer(); + + this.sentMessages[message.msg_id] = angular.extend(message, options || {}, {deferred: deferred}); + this.pendingMessages[message.msg_id] = 0; + + if (!options || !options.noShedule) { + this.sheduleRequest(); + } + + return deferred.promise; + }; + + MtpNetworker.prototype.pushResend = function(messageID, delay) { + var value = delay ? (new Date()).getTime() + delay : 0; + var sentMessage = this.sentMessages[messageID]; + if (sentMessage.container) { + for (var i = 0; i < sentMessage.inner.length; i++) { + this.pendingMessages[sentMessage.inner[i]] = value; + } + } else { + this.pendingMessages[messageID] = value; + } + + // dLog('Resend due', messageID, this.pendingMessages); + + this.sheduleRequest(delay); + }; + + MtpNetworker.prototype.getMsgKeyIv = function (msgKey, isOut) { + var authKey = this.authKey, + x = isOut ? 0 : 8; + + var promises = { + sha1a: MtpSha1Service.hash(msgKey.concat(authKey.slice(x, x + 32))), + sha1b: MtpSha1Service.hash(authKey.slice(32 + x, 48 + x).concat(msgKey, authKey.slice(48 + x, 64 + x))), + sha1c: MtpSha1Service.hash(authKey.slice(64 + x, 96 + x).concat(msgKey)), + sha1d: MtpSha1Service.hash(msgKey.concat(authKey.slice(96 + x, 128 + x))) + }; + + return $q.all(promises).then(function (result) { + var aesKey = result.sha1a.slice(0, 8).concat(result.sha1b.slice(8, 20), result.sha1c.slice(4, 16)); + var aesIv = result.sha1a.slice(8, 20).concat(result.sha1b.slice(0, 8), result.sha1c.slice(16, 20), result.sha1d.slice(0, 8)); + + return [aesKey, aesIv]; + }); + }; + + + MtpNetworker.prototype.performSheduledRequest = function() { + // dLog('start sheduled'); + delete this.nextReq; + if (this.pendingAcks.length) { + var ackMsgIDs = []; + for (var i = 0; i < this.pendingAcks.length; i++) { + ackMsgIDs.push(this.pendingAcks[i]); + } + // dLog('acking messages', ackMsgIDs); + this.wrapMtpMessage({_: 'msgs_ack', msg_ids: ackMsgIDs}, {notContentRelated: true, noShedule: true}); + } + + if (this.pendingResends.length) { + var resendMsgIDs = []; + for (var i = 0; i < this.pendingResends.length; i++) { + resendMsgIDs.push(this.pendingResends[i]); + } + // dLog('resendReq messages', resendMsgIDs); + this.wrapMtpMessage({_: 'msg_resend_req', msg_ids: resendMsgIDs}, {noShedule: true}); + } + + var messages = [], + message, + messagesByteLen = 0, + currentTime = (new Date()).getTime(), + self = this; + + angular.forEach(this.pendingMessages, function (value, messageID) { + if (!value || value >= currentTime) { + if (message = self.sentMessages[messageID]) { + messages.push(message); + messagesByteLen += message.body.length + 32; + } else { + // dLog(message, messageID); + } + delete self.pendingMessages[messageID]; + } + }); + + if (!messages.length) { + // dLog('no sheduled messages'); + return; + } + + var noResponseMsgs = []; + + if (messages.length > 1) { + var container = new TLSerialization({mtproto: true, startMaxLength: messagesByteLen + 64}); + container.storeInt(0x73f1f8dc, 'CONTAINER[id]'); + container.storeInt(messages.length, 'CONTAINER[count]'); + var onloads = []; + var innerMessages = []; + for (var i = 0; i < messages.length; i++) { + container.storeLong(messages[i].msg_id, 'CONTAINER[' + i + '][msg_id]'); + innerMessages.push(messages[i].msg_id); + container.storeInt(messages[i].seq_no, 'CONTAINER[' + i + '][seq_no]'); + container.storeInt(messages[i].body.length, 'CONTAINER[' + i + '][bytes]'); + container.storeRawBytes(messages[i].body, 'CONTAINER[' + i + '][body]'); + if (messages[i].noResponse) { + noResponseMsgs.push(messages[i].msg_id); + } + } + + var containerSentMessage = { + msg_id: MtpMessageIdGenerator.generateID(), + seq_no: this.generateSeqNo(true), + container: true, + inner: innerMessages + } + + message = angular.extend({body: container.getBytes()}, containerSentMessage); + + this.sentMessages[message.msg_id] = containerSentMessage; + + // dLog('Container', innerMessages, message.msg_id, message.seq_no); + } else { + if (message.noResponse) { + noResponseMsgs.push(message.msg_id); + } + this.sentMessages[message.msg_id] = message; + } + + this.pendingAcks = []; + var self = this; + + this.sendEncryptedRequest(message).then(function (result) { + self.parseResponse(result.data); + + if (noResponseMsgs.length) { + $timeout(function () { + angular.forEach(noResponseMsgs, function (msgID) { + if (self.sentMessages[msgID]) { + var deferred = self.sentMessages[msgID].deferred; + delete self.sentMessages[msgID]; + deferred.resolve(); + } + }); + }, 200); + } + }); + }; + + MtpNetworker.prototype.getEncryptedMessage = function (bytes) { + var self = this; + + // dLog('enc', bytes); + + return MtpSha1Service.hash(bytes).then(function (bytesHash) { + // dLog('bytesHash', bytesHash); + var msgKey = bytesHash.slice(-16); + return self.getMsgKeyIv(msgKey, true).then(function (keyIv) { + // dLog('keyIv', keyIv); + return MtpAesService.encrypt(bytes, keyIv[0], keyIv[1]).then(function (encryptedBytes) { + // dLog('encryptedBytes', encryptedBytes); + return { + bytes: encryptedBytes, + msgKey: msgKey + }; + }) + }) + }) + }; + + MtpNetworker.prototype.getDecryptedMessage = function (msgKey, encryptedData) { + return this.getMsgKeyIv(msgKey, false).then(function (keyIv) { + return MtpAesService.decrypt(encryptedData, keyIv[0], keyIv[1]); + }); + }; + + MtpNetworker.prototype.sendEncryptedRequest = function (message) { + var self = this; + // dLog('send encrypted', message); + // console.trace(); + var data = new TLSerialization({startMaxLength: message.body.length + 64}); + + data.storeIntBytes(this.serverSalt, 64, 'salt'); + data.storeIntBytes(this.sessionID, 64, 'session_id'); + + data.storeLong(message.msg_id, 'message_id'); + data.storeInt(message.seq_no, 'seq_no'); + + data.storeInt(message.body.length, 'message_data_length'); + data.storeRawBytes(message.body, 'message_data'); + + return this.getEncryptedMessage(data.getBytes()).then(function (encryptedResult) { + // dLog('got enc result', encryptedResult); + var request = new TLSerialization({startMaxLength: encryptedResult.bytes.length + 256}); + request.storeIntBytes(self.authKeyID, 64, 'auth_key_id'); + request.storeIntBytes(encryptedResult.msgKey, 128, 'msg_key'); + request.storeRawBytes(encryptedResult.bytes, 'encrypted_data'); + + delete $http.defaults.headers.post['Content-Type']; + delete $http.defaults.headers.common['Accept']; + + return $http.post('http://' + MtpDcConfigurator.chooseServer(self.dcID) + '/apiw1', request.getArray(), { + responseType: 'arraybuffer', + transformRequest: null + }); + }); + }; + + MtpNetworker.prototype.parseResponse = function (responseBuffer) { + var self = this; + + var deserializer = new TLDeserialization(responseBuffer); + + var authKeyID = deserializer.fetchIntBytes(64, 'auth_key_id'); + if (!bytesCmp(authKeyID, this.authKeyID)) { + throw new Error('Invalid server auth_key_id: ' + bytesToHex(authKeyID)); + } + var msgKey = deserializer.fetchIntBytes(128, 'msg_key'); + + var dataLength = responseBuffer.byteLength - deserializer.getOffset(); + var encryptedData = deserializer.fetchRawBytes(dataLength, 'encrypted_data'); + + this.getDecryptedMessage(msgKey, encryptedData).then(function (dataWithPadding) { + var buffer = bytesToArrayBuffer(dataWithPadding); + + var deserializer = new TLDeserialization(buffer, {mtproto: true}); + + var salt = deserializer.fetchIntBytes(64, 'salt'); + var sessionID = deserializer.fetchIntBytes(64, 'session_id'); + var messageID = deserializer.fetchLong('message_id'); + + var seqNo = deserializer.fetchInt('seq_no'); + + var messageBody = deserializer.fetchRawBytes(false, 'message_data'); + + var offset = deserializer.getOffset(); + + MtpSha1Service.hash(dataWithPadding.slice(0, offset)).then(function (dataHashed) { + if (!bytesCmp(msgKey, dataHashed.slice(-16))) { + throw new Error('server msgKey mismatch'); + } + + var buffer = bytesToArrayBuffer(messageBody); + var deserializer = new TLDeserialization(buffer, {mtproto: true}); + + var response = deserializer.fetchObject('', 'INPUT'); + + // dLog('Server response', response); + + self.processResponse(response, messageID, sessionID, seqNo); + }); + }); + }; + + MtpNetworker.prototype.applyServerSalt = function (newServerSalt) { + var serverSalt = longToBytes(newServerSalt); + + var storeObj = {}; + storeObj['dc' + this.dcID + '_server_salt'] = bytesToHex(serverSalt); + AppConfigManager.set(storeObj); + + this.serverSalt = serverSalt; + return true; + }; + + MtpNetworker.prototype.sheduleRequest = function (delay) { + var nextReq = new Date() + delay; + + if (delay && this.nextReq && this.nextReq <= nextReq) { + return false; + } + + // dLog('shedule req', delay); + // console.trace(); + + clearTimeout(this.nextReqTO); + + this.nextReqTO = setTimeout(this.performSheduledRequest.bind(this), delay || 0); + this.nextReq = nextReq; + }; + + MtpNetworker.prototype.onSessionCreate = function (sessionID, messageID) { + dLog('New session created', bytesToHex(sessionID)); + }; + + MtpNetworker.prototype.ackMessage = function (msgID) { + // dLog('ack message', msgID); + this.pendingAcks.push(msgID); + this.sheduleRequest(30000); + }; + + MtpNetworker.prototype.reqResendMessage = function (msgID) { + dLog('req resend', msgID); + this.pendingResends.push(msgID); + this.sheduleRequest(100); + }; + + MtpNetworker.prototype.processResponse = function (response, messageID, sessionID, seqNo) { + return this.processMessage(response, messageID, sessionID); + }; + + MtpNetworker.prototype.processMessageAck = function (messageID) { + var sentMessage = this.sentMessages[messageID]; + if (sentMessage && !sentMessage.acked) { + delete sentMessage.body; + sentMessage.acked = true; + + return true; + } + + return false; + }; + + MtpNetworker.prototype.processError = function (rawError) { + var matches = (rawError.error_message || '').match(/^([A-Z_0-9]+\b)(: (.+))?/) || []; + rawError.error_code = uintToInt(rawError.error_code); + + return { + code: !rawError.error_code || rawError.error_code <= 0 ? 500 : rawError.error_code, + type: matches[1] || 'UNKNOWN', + description: matches[3] || ('CODE#' + rawError.error_code + ' ' + rawError.error_message), + originalError: rawError + }; + }; + + + MtpNetworker.prototype.processMessage = function (message, messageID, sessionID) { + // dLog('process message', message, messageID, sessionID); + switch (message._) { + case 'msg_container': + var len = message.messages.length; + for (var i = 0; i < len; i++) { + this.processMessage(message.messages[i], messageID, sessionID); + } + break; + + case 'bad_server_salt': + var sentMsg = this.sentMessages[message.bad_msg_id]; + if (!sentMsg || sentMsg.seq_no != message.bad_msg_seqno) { + dLog(message.bad_msg_id, message.bad_msg_seqno); + throw new Error('Bad server salt for invalid message'); + } + + this.applyServerSalt(message.new_server_salt); + this.pushResend(message.bad_msg_id); + this.ackMessage(messageID); + break; + + case 'message': + this.serverMessages.push(message.msg_id); + this.processMessage(message.body, message.msg_id, sessionID); + break; + + case 'new_session_created': + this.ackMessage(messageID); + + this.processMessageAck(message.first_msg_id); + this.applyServerSalt(message.server_salt); + this.onSessionCreate(sessionID, messageID); + break; + + case 'msgs_ack': + for (var i = 0; i < message.msg_ids.length; i++) { + this.processMessageAck(message.msg_ids[i]); + } + break; + + case 'msg_detailed_info': + if (!this.sentMessages[message.msg_id]) { + this.ackMessage(message.answer_msg_id); + break; + } + case 'msg_new_detailed_info': + // this.ackMessage(message.answer_msg_id); + this.reqResendMessage(message.answer_msg_id); + break; + + case 'rpc_result': + this.ackMessage(messageID); + + var sentMessageID = message.req_msg_id, + sentMessage = this.sentMessages[sentMessageID]; + + this.processMessageAck(sentMessageID); + if (sentMessage) { + var deferred = sentMessage.deferred; + if (message.result._ == 'rpc_error') { + var error = this.processError(message.result); + dLog('rpc error', error) + if (deferred) { + deferred.reject(error) + } + } else { + if (deferred) { + dLog('rpc response', message.result); + sentMessage.deferred.resolve(message.result); + } + if (sentMessage.isAPI) { + this.connectionInited = true; + } + } + + delete this.sentMessages[sentMessageID]; + } + break; + + default: + this.ackMessage(messageID); + + // dLog('Update', message); + if (updatesProcessor) { + updatesProcessor(message); + } + break; + + } + }; + + return { + getNetworker: function (dcID, authKey, serverSalt) { + return new MtpNetworker(dcID, authKey, serverSalt); + }, + setUpdatesProcessor: function (callback) { + updatesProcessor = callback; + } + }; + +}). + +factory('MtpApiManager', function (AppConfigManager, MtpAuthorizer, MtpNetworkerFactory, $q) { + var cachedNetworkers = {}, + cachedExportPromise = {}, + baseDcID = false; + + AppConfigManager.get('dc').then(function (dcID) { + if (dcID) { + baseDcID = dcID; + } + }); + + function mtpSetUserAuth (dcID, userAuth) { + AppConfigManager.set({ + dc: dcID, + user_auth: angular.extend({dcID: dcID}, userAuth) + }); + + baseDcID = dcID; + } + + function mtpLogOut () { + return mtpInvokeApi('auth.logOut').then(function () { + AppConfigManager.remove('dc', 'user_auth'); + + baseDcID = false; + }); + } + + function mtpGetNetworker (dcID) { + if (!dcID) { + throw new Exception('get Networker without dcID'); + } + + if (cachedNetworkers[dcID] !== undefined) { + return $q.when(cachedNetworkers[dcID]); + } + + var deferred = $q.defer(), + ak = 'dc' + dcID + '_auth_key', + ssk = 'dc' + dcID + '_server_salt'; + + AppConfigManager.get(ak, ssk).then(function (result) { + + if (cachedNetworkers[dcID] !== undefined) { + return deferred.resolve(cachedNetworkers[dcID]); + } + + var authKeyHex = result[0], + serverSaltHex = result[1]; + // dLog('ass', dcID, authKeyHex, serverSaltHex); + if (authKeyHex && authKeyHex.length == 512) { + var authKey = bytesFromHex(authKeyHex); + var serverSalt = bytesFromHex(serverSaltHex); + + return deferred.resolve(cachedNetworkers[dcID] = MtpNetworkerFactory.getNetworker(dcID, authKey, serverSalt)); + } + + MtpAuthorizer.auth(dcID).then(function (auth) { + var storeObj = {}; + storeObj[ak] = bytesToHex(auth.authKey); + storeObj[ssk] = bytesToHex(auth.serverSalt); + AppConfigManager.set(storeObj); + + deferred.resolve( + cachedNetworkers[dcID] = MtpNetworkerFactory.getNetworker(dcID, auth.authKey, auth.serverSalt) + ); + }, function (error) { + dLog('Get networker error', error, error.stack); + deferred.reject(error); + }); + + }); + + return deferred.promise; + }; + + function mtpInvokeApi (method, params, options) { + var deferred = $q.defer(); + + options = options || {}; + var dcID = options.dcID || baseDcID || 1; + + var cachedNetworker; + + mtpGetNetworker(dcID).then(function (networker) { + return (cachedNetworker = networker).wrapApiCall(method, params, options).then( + function (result) { + deferred.resolve(result); + // setTimeout(function () { + // deferred.resolve(result); + // },1000); + }, + function (error) { + dLog('error', error.code, error.type, baseDcID, dcID); + if (error.code == 401 && error.type == 'AUTH_KEY_UNREGISTERED' && baseDcID && dcID != baseDcID) { + if (cachedExportPromise[dcID] === undefined) { + var exportDeferred = $q.defer(); + + mtpInvokeApi('auth.exportAuthorization', {dc_id: dcID}).then(function (exportedAuth) { + mtpInvokeApi('auth.importAuthorization', { + id: exportedAuth.id, + bytes: exportedAuth.bytes + }, {dcID: dcID}).then(function () { + exportDeferred.resolve(); + }, function (e) { + exportDeferred.reject(e); + }) + }, function (e) { + exportDeferred.reject(e) + }); + + cachedExportPromise[dcID] = exportDeferred.promise; + } + + // dLog('promise', cachedExportPromise[dcID]); + + cachedExportPromise[dcID] = cachedExportPromise[dcID].then(function () { + (cachedNetworker = networker).wrapApiCall(method, params, options).then(function (result) { + deferred.resolve(result); + }, function (error) { + deferred.reject(error); + }); + }, function (error) { + deferred.reject(error); + }); + } else { + deferred.reject(error); + } + }); + }); + + return deferred.promise; + }; + + function mtpGetUserID () { + var deferred = $q.defer(); + + AppConfigManager.get('user_auth').then(function (auth) { + deferred.resolve(auth.id || 0); + }); + + return deferred.promise; + } + + return { + getUserID: mtpGetUserID, + invokeApi: mtpInvokeApi, + setUserAuth: mtpSetUserAuth, + logOut: mtpLogOut + } +}). + + +factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { + + var cachedFS = false; + var apiUploadPromise = $q.when(); + var cachedSavePromises = {}; + var cachedDownloadPromises = {}; + + var downloadPull = []; + var downloadActive = 0; + var downloadLimit = 5; + + function downloadRequest(cb, activeDelta) { + var deferred = $q.defer(); + downloadPull.push({cb: cb, deferred: deferred, activeDelta: activeDelta}); + downloadCheck(); + + return deferred.promise; + }; + + var index = 0; + + function downloadCheck() { + if (downloadActive >= downloadLimit || !downloadPull.length) { + return false; + } + + var data = downloadPull.shift(), + activeDelta = data.activeDelta || 1; + + downloadActive += activeDelta; + + var a = index++; + data.cb() + .then(function (result) { + downloadActive -= activeDelta; + downloadCheck(); + + data.deferred.resolve(result); + + }, function (error) { + downloadActive -= activeDelta; + downloadCheck(); + + data.deferred.reject(error); + }) + }; + + function requestFS (argument) { + if (cachedFS) { + return $q.when(cachedFS); + } + + var deferred = $q.defer(); + + $window.requestFileSystem = $window.requestFileSystem || $window.webkitRequestFileSystem; + + $window.requestFileSystem($window.TEMPORARY, 5*1024*1024, function (fs) { + cachedFS = fs; + deferred.resolve(); + }, function (e) { + deferred.reject(e); + }); + + return deferred.promise; + }; + + function fileWriteBytes(fileWriter, bytes) { + var deferred = $q.defer(); + + fileWriter.onwriteend = function(e) { + deferred.resolve(); + }; + fileWriter.onerror = function (e) { + deferred.reject(); + }; + + if (false) { // is file bytes + fileWriter.write(bytes); + } else { + fileWriter.write(new Blob([bytesToArrayBuffer(bytes)])); + } + + return deferred.promise; + } + + function getFileName(location) { + switch (location._) { + case 'inputVideoFileLocation': + return 'video' + location.id + '.mp4'; + + case 'inputDocumentFileLocation': + return 'doc' + location.id; + } + return location.volume_id + '_' + location.local_id + '_' + location.secret + '.jpg'; + }; + + function getTempFileName(file) { + var size = file.size || -1; + var random = nextRandomInt(0xFFFFFFFF); + return '_temp' + random + '_' + size; + }; + + function getCachedFile (location) { + var fileName = getFileName(location); + + if (cachedSavePromises[fileName]) { + return cachedSavePromises[fileName]; + } + var deferred = $q.defer(), + errorHandler = function (error) { + deferred.reject(); + }; + + requestFS().then(function () { + cachedFS.root.getFile(fileName, {create: false}, function(fileEntry) { + deferred.resolve(fileEntry.toURL()); + }, errorHandler); + }, errorHandler); + + return deferred.promise; + } + + function saveSmallFile (location, bytes) { + var fileName = getFileName(location); + + if (cachedSavePromises[fileName]) { + return cachedSavePromises[fileName]; + } + var deferred = $q.defer(), + cacheFileWriter, + errorHandler = function (error) { + deferred.reject(error); + if (cacheFileWriter) cacheFileWriter.truncate(); + }; + + requestFS().then(function () { + cachedFS.root.getFile(fileName, {create: false}, function(fileEntry) { + deferred.resolve(fileEntry.toURL()); + }, function () { + cachedFS.root.getFile(fileName, {create: true}, function(fileEntry) { + fileEntry.createWriter(function (fileWriter) { + cacheFileWriter = fileWriter; + fileWriteBytes(fileWriter, bytes).then(function () { + deferred.resolve(fileEntry.toURL()); + }, errorHandler); + }, errorHandler); + }, errorHandler); + }); + }, errorHandler); + + return cachedSavePromises[fileName] = deferred.promise; + } + + function downloadSmallFile(location) { + // dLog('dload small', location); + var fileName = getFileName(location), + cachedPromise = cachedSavePromises[fileName] || cachedDownloadPromises[fileName]; + + if (cachedPromise) { + return cachedPromise; + } + + var deferred = $q.defer(), + cacheFileWriter, + errorHandler = function (error) { + deferred.reject(error); + if (cacheFileWriter) cacheFileWriter.truncate(); + }, + doDownload = function () { + cachedFS.root.getFile(fileName, {create: true}, function(fileEntry) { + var downloadPromise = downloadRequest(function () { + // dLog('next small promise'); + return MtpApiManager.invokeApi('upload.getFile', { + location: angular.extend({}, location, {_: 'inputFileLocation'}), + offset: 0, + limit: 0 + }, {dcID: location.dc_id}); + }); + + fileEntry.createWriter(function (fileWriter) { + cacheFileWriter = fileWriter; + downloadPromise.then(function (result) { + fileWriteBytes(fileWriter, result.bytes).then(function () { + // dLog('Success', location, fileEntry.toURL()); + deferred.resolve(fileEntry.toURL()); + }, errorHandler); + }, errorHandler); + }, errorHandler); + }, errorHandler); + }; + + requestFS().then(function () { + cachedFS.root.getFile(fileName, {create: false}, function(fileEntry) { + fileEntry.file(function(file) { + if (file.size) { + deferred.resolve(fileEntry.toURL()); + } else { + dLog('Small file empty', file); + doDownload(); + } + }, errorHandler); + }, doDownload); + }, errorHandler); + + return cachedDownloadPromises[fileName] = deferred.promise; + } + + function downloadFile (dcID, location, size, fileEntry) { + dLog('dload file', dcID, location, size); + var fileName = getFileName(location), + cachedPromise = cachedSavePromises[fileName] || cachedDownloadPromises[fileName]; + + if (cachedPromise) { + return cachedPromise; + } + + var deferred = $q.defer(), + errorHandler = function (error) { + console.error(error); + // dLog('fail'); + deferred.reject(error); + if (cacheFileWriter) cacheFileWriter.truncate(); + }, + saveToFileEntry = function (fileEntry) { + fileEntry.createWriter(function (fileWriter) { + cacheFileWriter = fileWriter; + + // var limit = size > 102400 ? 65536 : 4096; + // var limit = size > 30400 ? 524288 : 4096; + var limit = size > 30400 ? 20480 : 4096; + var writeFilePromise = $q.when(), + writeFileDeferred; + for (var offset = 0; offset < size; offset += limit) { + writeFileDeferred = $q.defer(); + (function (isFinal, offset, writeFileDeferred, writeFilePromise) { + return downloadRequest(function () { + // dLog('next big promise'); + return MtpApiManager.invokeApi('upload.getFile', { + location: location, + offset: offset, + limit: limit + }, {dcID: dcID}); + + }, 6).then(function (result) { + + // dLog('waiting for file promise', offset); + writeFilePromise.then(function () { + // dLog('resolved file promise', offset); + + return fileWriteBytes(fileWriter, result.bytes).then(function () { + + // dLog('resolve file promise', offset); + writeFileDeferred.resolve(); + + }, errorHandler).then(function () { + + if (isFinal) { + deferred.resolve(fileEntry.toURL('image/jpeg')); + } else { + // dLog('notify', {done: offset + limit, total: size}); + deferred.notify({done: offset + limit, total: size}); + }; + + }); + + }); + + }); + + })(offset + limit >= size, offset, writeFileDeferred, writeFilePromise); + + writeFilePromise = writeFileDeferred.promise; + + } + }, errorHandler); + + }, + doDownload = function () { + cachedFS.root.getFile(fileName, {create: true}, saveToFileEntry, errorHandler); + }; + + if (fileEntry) { + saveToFileEntry(fileEntry); + } else { + requestFS().then(function () { + cachedFS.root.getFile(fileName, {create: false}, function(fileEntry) { + fileEntry.file(function(file) { + dLog('check size', file.size, size); + if (file.size >= size && false) { + deferred.resolve(fileEntry.toURL()); + } else { + dLog('File bad size', file, size); + doDownload(); + } + }, errorHandler); + }, doDownload); + }, errorHandler); + } + + return cachedDownloadPromises[fileName] = deferred.promise; + } + + function writeFile (file) { + dLog('write file', file); + var fileName = getTempFileName(file); + + var deferred = $q.defer(), + cacheFileWriter, + errorHandler = function (error) { + dLog('fail'); + deferred.reject(error); + if (cacheFileWriter) cacheFileWriter.truncate(); + }; + + requestFS().then(function () { + cachedFS.root.getFile(fileName, {create: false}, function(fileEntry) { + deferred.resolve(fileEntry); + }, function () { + cachedFS.root.getFile(fileName, {create: true}, function(fileEntry) { + fileEntry.createWriter(function (fileWriter) { + cacheFileWriter = fileWriter; + fileWriteBytes(fileWriter, file).then(function () { + deferred.resolve(fileEntry); + }, errorHandler); + }, errorHandler); + }); + }); + }); + }; + + function uploadFile (file) { + var fileSize = file.size, + // partSize = fileSize > 102400 ? 65536 : 4096, + partSize = fileSize > 102400 ? 524288 : 4096, + totalParts = Math.ceil(fileSize / partSize), + doneParts = 0; + + if (totalParts > 1500) { + return $q.reject({type: 'FILE_TOO_BIG'}); + } + + var fileID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)], + deferred = $q.defer(), + errorHandler = function (error) { + dLog('error', error); + deferred.reject(error); + }, + part = 0, + offset, + resultInputFile = { + _: 'inputFile', + id:fileID, + parts: totalParts, + name: file.name, + md5_checksum: '' + }; + + + var fileReadPromise = $q.when(); + + for (offset = 0; offset < fileSize; offset += partSize) { + (function (offset, part) { + fileReadPromise = fileReadPromise.then(function () { + var fileReadDeferred = $q.defer(); + + var reader = new FileReader(); + var blob = file.slice(offset, offset + partSize); + + reader.onloadend = function (e) { + if (e.target.readyState != FileReader.DONE) { + return; + } + var apiCurPromise = apiUploadPromise = apiUploadPromise.then(function () { + return MtpApiManager.invokeApi('upload.saveFilePart', { + file_id: fileID, + file_part: part, + bytes: bytesFromArrayBuffer(e.target.result) + }, {startMaxLength: partSize + 256}); + }, errorHandler); + + apiCurPromise.then(function (result) { + doneParts++; + fileReadDeferred.resolve(); + if (doneParts >= totalParts) { + deferred.resolve(resultInputFile); + } else { + dLog('Progress', doneParts * partSize / fileSize); + deferred.notify({done: doneParts * partSize, total: fileSize}); + } + }, errorHandler); + }; + + reader.readAsArrayBuffer(blob); + + return fileReadDeferred.promise; + }); + })(offset, part++); + } + + return deferred.promise; + } + + + return { + getCachedFile: getCachedFile, + downloadFile: downloadFile, + downloadSmallFile: downloadSmallFile, + saveSmallFile: saveSmallFile, + uploadFile: uploadFile + }; +}) + + + + + + diff --git a/app/js/lib/pq_worker.js b/app/js/lib/pq_worker.js new file mode 100644 index 00000000..3385fd8a --- /dev/null +++ b/app/js/lib/pq_worker.js @@ -0,0 +1,12 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +importScripts('mtproto.js', 'jsbn.js'); + +onmessage = function (e) { + postMessage(pqPrimeFactorization(e.data)); +} \ No newline at end of file diff --git a/app/js/lib/sha1_worker.js b/app/js/lib/sha1_worker.js new file mode 100644 index 00000000..44a35fb5 --- /dev/null +++ b/app/js/lib/sha1_worker.js @@ -0,0 +1,14 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +importScripts('mtproto.js', '../../vendor/cryptoJS/crypto.js'); + +onmessage = function (e) { + var taskID = e.data.taskID; + + postMessage({taskID: taskID, result: sha1Hash(e.data.bytes)}); +} \ No newline at end of file diff --git a/app/js/services.js b/app/js/services.js new file mode 100644 index 00000000..f2569107 --- /dev/null +++ b/app/js/services.js @@ -0,0 +1,1439 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +'use strict'; + +/* Services */ + +angular.module('myApp.services', []) + +.service('AppConfigManager', function ($q) { + var testPrefix = window._testMode ? 't_' : ''; + var cache = {}; + var useLs = !window.chrome || !chrome.storage || !chrome.storage.local; + + function getValue() { + var keys = Array.prototype.slice.call(arguments), + result = [], + single = keys.length == 1, + allFound = true; + + for (var i = 0; i < keys.length; i++) { + keys[i] = testPrefix + keys[i]; + } + + angular.forEach(keys, function (key) { + if (cache[key] !== undefined) { + result.push(cache[key]); + } + else if (useLs) { + var value = localStorage.getItem(key); + value = (value === undefined || value === null) ? false : JSON.parse(value); + result.push(cache[key] = value); + } + else { + allFound = false; + } + }); + + if (allFound) { + return $q.when(single ? result[0] : result); + } + + var deferred = $q.defer(); + + // dLog('get', keys); + chrome.storage.local.get(keys, function (resultObj) { + // dLog('got', resultObj); + result = []; + angular.forEach(keys, function (key) { + var value = resultObj[key]; + // dLog('p1', key, value); + value = value === undefined || value === null ? false : JSON.parse(value); + // dLog('p2', value); + result.push(cache[key] = value); + }); + + // dLog('got parsed', result); + deferred.resolve(single ? result[0] : result); + }); + + return deferred.promise; + }; + + function setValue(obj) { + var keyValues = {}; + angular.forEach(obj, function (value, key) { + keyValues[testPrefix + key] = JSON.stringify(value); + cache[testPrefix + key] = value; + }); + + if (useLs) { + angular.forEach(keyValues, function (value, key) { + localStorage.setItem(key, value); + }); + return $q.when(); + } + + var deferred = $q.defer(); + + chrome.storage.local.set(keyValues, function () { + deferred.resolve(); + }); + + return deferred.promise; + }; + + function removeValue () { + var keys = Array.prototype.slice.call(arguments); + + for (var i = 0; i < keys.length; i++) { + keys[i] = testPrefix + keys[i]; + } + + angular.forEach(keys, function(key){ + delete cache[key]; + }); + + if (useLs) { + angular.forEach(keys, function(key){ + localStorage.removeItem(key); + }); + + return $q.when(); + } + + var deferred = $q.defer(); + + chrome.storage.local.remove(keys, function () { + deferred.resolve(); + }); + + return deferred.promise; + }; + + return { + get: getValue, + set: setValue, + remove: removeValue + }; +}) + +.service('AppUsersManager', function ($rootScope, $modal, MtpApiFileManager, MtpApiManager, RichTextProcessor) { + var users = {}; + + function saveApiUsers (apiUsers) { + angular.forEach(apiUsers, saveApiUser); + }; + + function saveApiUser (apiUser) { + if (!angular.isObject(apiUser)) { + return; + } + + if (apiUser.first_name) { + apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.first_name, {noLinks: true, noLinebreaks: true}); + apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.first_name + ' ' + (apiUser.last_name || ''), {noLinks: true, noLinebreaks: true}); + } else { + apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || 'DELETED'; + apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || 'DELETED'; + } + + if (users[apiUser.id] === undefined) { + users[apiUser.id] = apiUser; + } else { + angular.extend(users[apiUser.id], apiUser); + } + }; + + function getUser (id) { + if (angular.isObject(id)) { + return id; + } + return users[id] || {id: id, deleted: true}; + } + + function getUserPhoto(id, placeholder) { + var user = getUser(id); + + return { + placeholder: 'img/placeholders/' + placeholder + 'Avatar'+((Math.abs(id) % 8) + 1)+'@2x.png', + location: user && user.photo && user.photo.photo_small + }; + } + + function getUserString (id) { + var user = getUser(id); + return 'u' + id + (user.access_hash ? '_' + user.access_hash : ''); + } + + function getUserInput (id) { + var user = getUser(id); + if (user._ == 'userSelf') { + return {_: 'inputUserSelf'}; + } + return { + _: 'inputUserForeign', + user_id: id, + access_hash: user.access_hash || 0 + }; + } + + function wrapForFull (id) { + var user = getUser(id); + + user.thumb = { + placeholder: 'img/placeholders/UserAvatar'+((Math.abs(id) % 8) + 1)+'@2x.png', + location: user && user.photo && user.photo.photo_small, + width: 120, + height: 120, + size: 0 + }; + user.peerString = getUserString(id); + + return user; + } + + function openUser (userID, accessHash) { + var scope = $rootScope.$new(); + scope.userID = userID; + + var modalInstance = $modal.open({ + templateUrl: 'partials/user_modal.html', + controller: 'UserModalController', + scope: scope, + windowClass: 'user_modal_window', + resolve: { + userFull: MtpApiManager.invokeApi('users.getFullUser', { + id: getUserInput(userID) + }).then(function (result) { + saveApiUser(result.user); + return result; + }) + } + }); + } + + $rootScope.openUser = openUser; + + $rootScope.$on('apiUpdate', function (e, update) { + // dLog('on apiUpdate', update); + switch (update._) { + case 'updateUserStatus': + var userID = update.user_id; + if (users[userID]) { + users[userID].status = update.status; + $rootScope.$broadcast('user_update', userID); + } + break; + + case 'updateUserPhoto': + var userID = update.user_id; + if (users[userID]) { + users[userID].photo = update.photo; + $rootScope.$broadcast('user_update', userID); + } + break; + } + }); + + + return { + saveApiUsers: saveApiUsers, + saveApiUser: saveApiUser, + getUser: getUser, + getUserPhoto: getUserPhoto, + getUserString: getUserString, + wrapForFull: wrapForFull, + openUser: openUser + } +}) + +.service('AppChatsManager', function ($rootScope, $modal, MtpApiFileManager, MtpApiManager, AppUsersManager, RichTextProcessor) { + var chats = {}; + + function saveApiChats (apiChats) { + angular.forEach(apiChats, saveApiChat); + }; + + function saveApiChat (apiChat) { + if (!angular.isObject(apiChat)) { + return; + } + apiChat.rTitle = RichTextProcessor.wrapRichText(apiChat.title, {noLinks: true, noLinebreaks: true}) || 'DELETED'; + if (chats[apiChat.id] === undefined) { + chats[apiChat.id] = apiChat; + } else { + angular.extend(chats[apiChat.id], apiChat); + } + }; + + function getChat (id) { + return chats[id] || {id: id, deleted: true}; + } + + function getChatPhoto(id, placeholder) { + var chat = getChat(id); + + return { + placeholder: 'img/placeholders/' + placeholder + 'Avatar'+((Math.abs(id) % 4) + 1)+'@2x.png', + location: chat && chat.photo && chat.photo.photo_small + }; + } + + function getChatString (id) { + var chat = getChat(id); + return 'g' + id; + } + + function wrapForFull (id, fullChat) { + var chatFull = angular.copy(fullChat), + chat = getChat(id); + + if (chatFull.participants._ == 'chatParticipants') { + angular.forEach(chatFull.participants.participants, function(participant){ + participant.user = AppUsersManager.getUser(participant.user_id); + participant.userPhoto = AppUsersManager.getUserPhoto(participant.user_id, 'User'); + participant.inviter = AppUsersManager.getUser(participant.inviter_id); + }); + } + + chatFull.thumb = { + placeholder: 'img/placeholders/GroupAvatar'+((Math.abs(id) % 4) + 1)+'@2x.png', + location: chat && chat.photo && chat.photo.photo_small, + width: 120, + height: 120, + size: 0 + }; + chatFull.peerString = getChatString(id); + chatFull.chat = chat; + + return chatFull; + } + + function openChat (chatID, accessHash) { + var scope = $rootScope.$new(); + scope.chatID = chatID; + + var modalInstance = $modal.open({ + templateUrl: 'partials/chat_modal.html', + controller: 'ChatModalController', + windowClass: 'chat_modal_window', + scope: scope, + resolve: { + fullChat: function () { + return MtpApiManager.invokeApi('messages.getFullChat', { + chat_id: chatID + }).then(function (result) { + saveApiChats(result.chats); + AppUsersManager.saveApiUsers(result.users); + return result.full_chat; + }) + } + } + }); + } + + $rootScope.openChat = openChat; + + + return { + saveApiChats: saveApiChats, + saveApiChat: saveApiChat, + getChat: getChat, + getChatPhoto: getChatPhoto, + getChatString: getChatString, + wrapForFull: wrapForFull, + openChat: openChat + } +}) + +.service('AppPeersManager', function (AppUsersManager, AppChatsManager) { + return { + getInputPeer: function (peerString) { + var isUser = peerString.charAt(0) == 'u', + peerParams = peerString.substr(1).split('_'); + + return isUser + ? {_: 'inputPeerForeign', user_id: peerParams[0], access_hash: peerParams[1]} + : {_: 'inputPeerChat', chat_id: peerParams[0]}; + }, + getInputPeerByID: function (peerID) { + if (peerID > 0) { + return { + _: 'inputPeerForeign', + user_id: peerID, + access_hash: AppUsersManager.getUser(peerID).access_hash || 0 + }; + } else if (peerID < 0) { + return { + _: 'inputPeerChat', + chat_id: -peerID + }; + } + }, + getOutputPeer: function (peerID) { + return peerID > 0 + ? {_: 'peerUser', user_id: peerID} + : {_: 'peerChat', chat_id: -peerID}; + }, + getPeerID: function (peerString) { + if (angular.isObject(peerString)) { + return peerString.user_id + ? peerString.user_id + : -peerString.chat_id; + } + var isUser = peerString.charAt(0) == 'u', + peerParams = peerString.substr(1).split('_'); + + return isUser ? peerParams[0] : -peerParams[0] || 0; + }, + getPeer: function (peerID) { + return peerID > 0 + ? AppUsersManager.getUser(peerID) + : AppChatsManager.getChat(-peerID); + }, + getPeerPhoto: function (peerID, userPlaceholder, chatPlaceholder) { + return peerID > 0 + ? AppUsersManager.getUserPhoto(peerID, userPlaceholder) + : AppChatsManager.getChatPhoto(-peerID, chatPlaceholder) + } + } +}) + +.service('AppMessagesManager', function ($q, $rootScope, $filter, $sanitize, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, MtpApiManager, RichTextProcessor) { + + var messagesStorage = {}; + var messagesForHistory = {}; + var historiesStorage = {}; + var dialogsStorage = {count: null, dialogs: []}; + + function getDialogs (offset, limit) { + if (dialogsStorage.count !== null && dialogsStorage.dialogs.length >= offset + limit) { + return $q.when({ + count: dialogsStorage.count, + dialogs: dialogsStorage.dialogs.slice(offset, offset + limit) + }); + } + + var deferred = $q.defer(); + + MtpApiManager.invokeApi('messages.getDialogs', { + offset: offset, + limit: limit, + max_id: 0 + }).then(function (dialogsResult) { + AppUsersManager.saveApiUsers(dialogsResult.users); + AppChatsManager.saveApiChats(dialogsResult.chats); + saveMessages(dialogsResult.messages); + + dialogsStorage.count = dialogsResult._ == 'messages.dialogsSlice' + ? dialogsResult.count + : dialogsResult.dialogs.length; + + angular.forEach(dialogsResult.dialogs, function (dialog) { + dialogsStorage.dialogs.push({ + peerID: AppPeersManager.getPeerID(dialog.peer), + top_message: dialog.top_message, + unread_count: dialog.unread_count + }); + }); + + deferred.resolve({ + count: dialogsStorage.count, + dialogs: dialogsStorage.dialogs.slice(offset, offset + limit) + }); + }, function (error) { + deferred.reject(error); + }); + + return deferred.promise; + } + + function getHistory (inputPeer, maxID, limit) { + + var peerID = AppPeersManager.getPeerID(inputPeer), + historyStorage = historiesStorage[peerID], + offset = 0; + + if (historyStorage === undefined) { + historyStorage = historiesStorage[peerID] = {count: null, history: []}; + } + + + if (maxID > 0) { + for (offset = 0; offset < historyStorage.history.length; offset++) { + if (maxID > historyStorage.history[offset]) { + break; + } + } + } + // dLog('history storage', angular.copy(historyStorage.history), maxID, offset); + + if (historyStorage.count !== null && historyStorage.history.length >= offset + limit) { + return $q.when({ + count: historyStorage.count, + history: historyStorage.history.slice(offset, offset + limit) + }); + } + + var deferred = $q.defer(); + + MtpApiManager.invokeApi('messages.getHistory', { + peer: inputPeer, + offset: offset, + limit: limit, + max_id: 0 + }).then(function (historyResult) { + AppUsersManager.saveApiUsers(historyResult.users); + AppChatsManager.saveApiChats(historyResult.chats); + saveMessages(historyResult.messages); + + historyStorage.count = historyResult._ == 'messages.messagesSlice' + ? historyResult.count + : historyResult.messages.length; + + offset = 0; + if (maxID > 0) { + for (offset = 0; offset < historyStorage.history.length; offset++) { + if (maxID > historyStorage.history[offset]) { + break; + } + } + } + + // dLog('history storage after', angular.copy(historyStorage.history), historyResult.messages, maxID, offset); + + historyStorage.history.splice(offset, historyStorage.history.length - offset); + angular.forEach(historyResult.messages, function (message) { + historyStorage.history.push(message.id); + }); + + deferred.resolve({ + count: historyStorage.count, + history: historyStorage.history.slice(offset, offset + limit) + }); + }, function (error) { + deferred.reject(error); + }); + + return deferred.promise; + } + + function processAffectedHistory (inputPeer, affectedHistory) { + if (!ApiUpdatesManager.saveSeq(affectedHistory.seq)) { + return false; + } + if (!affectedHistory.offset) { + return $q.when(); + } + + return MtpApiManager.invokeApi('messages.readHistory', { + peer: inputPeer, + offset: affectedHistory.offset, + max_id: 0 + }).then(function (affectedHistory) { + return processAffectedHistory(inputPeer, affectedHistory); + }); + } + + function readHistory (inputPeer) { + // dLog('start read'); + var peerID = AppPeersManager.getPeerID(inputPeer), + historyStorage = historiesStorage[peerID], + foundDialog = getDialogByPeerID(peerID); + + if (!historyStorage || + !historyStorage.history.length || + foundDialog[0] && !foundDialog[0].unread_count) { + // dLog('bad1'); + return false; + } + + var wasUnread = false; + // dLog(historyStorage); + for (i = 0; i < historyStorage.history.length; i++) { + messageID = historyStorage.history[i]; + message = messagesStorage[messageID]; + // dLog('ms', message); + if (message && !message.out) { + if (message.unread) { + // dLog('unread'); + wasUnread = true; + } else if (!wasUnread) { + // dLog('bad2'); + return false; + } + } + } + + var promise = MtpApiManager.invokeApi('messages.readHistory', { + peer: inputPeer, + offset: 0, + max_id: 0 + }).then(function (affectedHistory) { + return processAffectedHistory(inputPeer, affectedHistory); + }).then(function () { + if (foundDialog[0]) { + foundDialog[0].unread_count = 0; + $rootScope.$broadcast('dialog_unread', {peerID: peerID, count: 0}); + } + }); + + + var messageID, message, i, peerID, foundDialog, dialog; + for (i = 0; i < historyStorage.history.length; i++) { + messageID = historyStorage.history[i]; + message = messagesStorage[messageID]; + if (message && !message.out) { + message.unread = false; + if (messagesForHistory[messageID]) { + messagesForHistory[messageID].unread = false; + } + } + } + + return promise; + } + + function saveMessages (apiMessages) { + angular.forEach(apiMessages, function (apiMessage) { + messagesStorage[apiMessage.id] = apiMessage; + + if (apiMessage.media && apiMessage.media._ == 'messageMediaPhoto') { + AppPhotosManager.savePhoto(apiMessage.media.photo); + } + if (apiMessage.media && apiMessage.media._ == 'messageMediaVideo') { + AppVideoManager.saveVideo(apiMessage.media.video); + } + if (apiMessage.media && apiMessage.media._ == 'messageMediaDocument') { + AppDocsManager.saveDoc(apiMessage.media.document); + } + if (apiMessage.action && apiMessage.action._ == 'messageActionChatEditPhoto') { + AppPhotosManager.savePhoto(apiMessage.action.photo); + } + }); + } + + function getMessagePeer (message) { + var toID = message.to_id && AppPeersManager.getPeerID(message.to_id) || 0; + + if (toID < 0) { + return toID; + } else if (message.out) { + return toID + } + return message.from_id; + } + + function wrapForDialog (msgID, unreadCount) { + var message = angular.copy(messagesStorage[msgID]) || {id: msgID}; + + message.fromUser = AppUsersManager.getUser(message.from_id); + + if (message.chatID = message.to_id.chat_id) { + message.peerID = -message.chatID; + message.peerData = AppChatsManager.getChat(message.chatID); + message.peerString = AppChatsManager.getChatString(message.chatID); + } else { + message.peerID = message.out ? message.to_id.user_id : message.from_id; + message.peerData = AppUsersManager.getUser(message.peerID); + message.peerString = AppUsersManager.getUserString(message.peerID); + } + + message.peerPhoto = AppPeersManager.getPeerPhoto(message.peerID, 'User', 'Group'); + message.unreadCount = unreadCount; + + if (message._ == 'messageService' && message.action.user_id) { + message.action.user = AppUsersManager.getUser(message.action.user_id); + } + + if (message.message && message.message.length) { + message.richMessage = RichTextProcessor.wrapRichText(message.message.substr(0, 64), {noLinks: true, noLinebreaks: true}); + } + + + return message; + } + + function wrapForHistory (msgID) { + if (messagesForHistory[msgID] !== undefined) { + return messagesForHistory[msgID]; + } + + var message = angular.copy(messagesStorage[msgID]) || {id: msgID}; + + message.fromUser = AppUsersManager.getUser(message.from_id); + message.fromPhoto = AppUsersManager.getUserPhoto(message.from_id, 'User'); + + if (message.media) { + switch (message.media._) { + case 'messageMediaPhoto': + message.media.photo = AppPhotosManager.wrapForHistory(message.media.photo.id) + break; + + case 'messageMediaVideo': + message.media.video = AppVideoManager.wrapForHistory(message.media.video.id); + break; + } + + if (message.media.user_id) { + message.media.user = AppUsersManager.getUser(message.media.user_id); + message.media.userPhoto = AppUsersManager.getUserPhoto(message.media.user_id, 'User'); + } + } + else if (message.action) { + if (message.action._ == 'messageActionChatEditPhoto') { + message.action.photo = AppPhotosManager.wrapForHistory(message.action.photo.id); + } + + if (message.action.user_id) { + message.action.user = AppUsersManager.getUser(message.action.user_id); + message.action.userPhoto = AppUsersManager.getUserPhoto(message.action.user_id, 'User'); + } + } + + if (message.message && message.message.length) { + message.richMessage = RichTextProcessor.wrapRichText(message.message); + } + + return messagesForHistory[msgID] = message; + } + + function getDialogByPeerID (peerID) { + for (var i = 0; i < dialogsStorage.dialogs.length; i++) { + if (dialogsStorage.dialogs[i].peerID == peerID) { + return [dialogsStorage.dialogs[i], i]; + } + } + + return []; + } + + + $rootScope.$on('apiUpdate', function (e, update) { + dLog('on apiUpdate', update); + switch (update._) { + case 'updateNewMessage': + var message = update.message, + peerID = getMessagePeer(message), + historyStorage = historiesStorage[peerID]; + + if (historyStorage !== undefined) { + var topMsgID = historiesStorage[peerID].history[0]; + if (message.id <= topMsgID) { + return false; + } + } else { + historyStorage = historiesStorage[peerID] = {count: null, history: []}; + } + + saveMessages([message]); + + if (historyStorage.count !== null) { + historyStorage.count++; + } + historyStorage.history.unshift(message.id); + $rootScope.$broadcast('history_append', {peerID: peerID, messageID: message.id}); + + var foundDialog = getDialogByPeerID(peerID), + dialog; + + if (foundDialog.length) { + dialog = foundDialog[0]; + dialogsStorage.dialogs.splice(foundDialog[1], 1); + } else { + dialog = {peerID: peerID, unread_count: 0, top_message: false} + } + if (!message.out && message.unread) { + dialog.unread_count++; + } + dialog.top_message = message.id; + dialogsStorage.dialogs.unshift(dialog); + $rootScope.$broadcast('dialogs_update', dialog); + break; + + case 'updateReadMessages': + var dialogsUpdated = {}, + messageID, message, i, peerID, foundDialog, dialog; + for (i = 0; i < update.messages.length; i++) { + messageID = update.messages[i]; + message = messagesStorage[messageID]; + // dLog('read', messageID, message); + if (message) { + message.unread = false; + if (messagesForHistory[messageID]) { + messagesForHistory[messageID].unread = false; + } + peerID = getMessagePeer(message); + if (!message.out) { + foundDialog = getDialogByPeerID(peerID); + if (foundDialog) { + dialogsUpdated[peerID] = --foundDialog[0].unread_count; + } + } + } + } + + angular.forEach(dialogsUpdated, function(count, peerID) { + $rootScope.$broadcast('dialog_unread', {peerID: peerID, count: count}); + }); + break; + } + }); + + return { + getDialogs: getDialogs, + getHistory: getHistory, + readHistory: readHistory, + saveMessages: saveMessages, + getMessagePeer: getMessagePeer, + wrapForDialog: wrapForDialog, + wrapForHistory: wrapForHistory + } +}) + +.service('AppPhotosManager', function ($modal, $window, $rootScope, MtpApiFileManager, AppUsersManager) { + var photos = {}; + + function savePhoto (apiPhoto) { + photos[apiPhoto.id] = apiPhoto; + angular.forEach(apiPhoto.sizes, function (photoSize) { + if (photoSize._ == 'photoCachedSize') { + MtpApiFileManager.saveSmallFile(photoSize.location, photoSize.bytes); + + // Memory + photoSize.size = photoSize.bytes.length; + delete photoSize.bytes; + photoSize._ = 'photoSize'; + } + }); + }; + + function choosePhotoSize (photo, width, height) { + var bestPhotoSize = {_: 'photoSizeEmpty'}, + bestDiff = 0xFFFFFF; + + angular.forEach(photo.sizes, function (photoSize) { + var diff = Math.abs(photoSize.w * photoSize.h - width * height); + if (diff < bestDiff) { + bestPhotoSize = photoSize; + bestDiff = diff; + } + }); + + return bestPhotoSize; + } + + function wrapForHistory (photoID) { + var photo = angular.copy(photos[photoID]) || {_: 'photoEmpty'}, + width = 100, + height = 100, + thumbPhotoSize = choosePhotoSize(photo, width, height), + thumb = { + placeholder: 'img/placeholders/PhotoThumbConversation.jpg', + width: width, + height: height + }; + + // dLog('chosen photo size', photoID, thumbPhotoSize); + if (thumbPhotoSize && thumbPhotoSize._ != 'photoSizeEmpty') { + if (thumbPhotoSize.w > thumbPhotoSize.h) { + thumb.height = parseInt(thumbPhotoSize.h * width / thumbPhotoSize.w); + } else { + thumb.width = parseInt(thumbPhotoSize.w * height / thumbPhotoSize.h); + } + + thumb.location = thumbPhotoSize.location; + thumb.size = thumbPhotoSize.size; + } + + photo.thumb = thumb; + + return photo; + } + + function wrapForFull (photoID) { + var photo = wrapForHistory(photoID), + fullWidth = 542, + fullHeight = $($window).height() - 150, + fullPhotoSize = choosePhotoSize(photo, fullWidth, fullHeight), + full = { + placeholder: 'img/placeholders/PhotoThumbModal.jpg', + width: fullWidth, + height: fullHeight + }; + + if (fullPhotoSize && fullPhotoSize._ != 'photoSizeEmpty') { + if (fullPhotoSize.w > fullPhotoSize.h) { + full.height = parseInt(fullPhotoSize.h * fullWidth / fullPhotoSize.w); + } else { + full.width = parseInt(fullPhotoSize.w * fullHeight / fullPhotoSize.h); + if (full.width > fullWidth) { + full.height = parseInt(full.height * fullWidth / full.width); + full.width = fullWidth; + } + } + + full.location = fullPhotoSize.location; + full.size = fullPhotoSize.size; + } + + photo.full = full; + photo.fromUser = AppUsersManager.getUser(photo.user_id); + + return photo; + } + + function openPhoto (photoID, accessHash) { + var scope = $rootScope.$new(true); + scope.photoID = photoID; + + var modalInstance = $modal.open({ + templateUrl: 'partials/photo_modal.html', + controller: 'PhotoModalController', + scope: scope, + backdrop: 'static' + }); + } + + $rootScope.openPhoto = openPhoto; + + + return { + savePhoto: savePhoto, + wrapForHistory: wrapForHistory, + wrapForFull: wrapForFull, + openPhoto: openPhoto + } +}) + + +.service('AppVideoManager', function ($rootScope, $modal, $window, MtpApiFileManager, AppUsersManager) { + var videos = {}; + + function saveVideo (apiVideo) { + videos[apiVideo.id] = apiVideo; + + if (apiVideo.thumb && apiVideo.thumb._ == 'photoCachedSize') { + MtpApiFileManager.saveSmallFile(apiVideo.thumb.location, apiVideo.thumb.bytes); + + // Memory + apiVideo.thumb.size = apiVideo.thumb.bytes.length; + delete apiVideo.thumb.bytes; + apiVideo.thumb._ = 'photoSize'; + } + }; + + function wrapForHistory (videoID) { + var video = angular.copy(videos[videoID]), + width = 100, + height = 100, + thumbPhotoSize = video.thumb, + thumb = { + placeholder: 'img/placeholders/VideoThumbConversation.jpg', + width: width, + height: height + }; + + if (thumbPhotoSize && thumbPhotoSize._ != 'photoSizeEmpty') { + if (thumbPhotoSize.w > thumbPhotoSize.h) { + thumb.height = parseInt(thumbPhotoSize.h * width / thumbPhotoSize.w); + } else { + thumb.width = parseInt(thumbPhotoSize.w * height / thumbPhotoSize.h); + } + + thumb.location = thumbPhotoSize.location; + thumb.size = thumbPhotoSize.size; + } + + video.thumb = thumb; + + return video; + } + + function wrapForFull (videoID) { + var video = wrapForHistory(videoID), + fullWidth = 542, + fullHeight = $($window).height() - 150, + fullPhotoSize = video, + full = { + placeholder: 'img/placeholders/VideoThumbModal.jpg', + width: fullWidth, + height: fullHeight, + }; + + if (video.w > video.h) { + full.height = parseInt(video.h * fullWidth / video.w); + } else { + full.width = parseInt(video.w * fullHeight / video.h); + if (full.width > fullWidth) { + full.height = parseInt(full.height * fullWidth / full.width); + full.width = fullWidth; + } + } + + video.full = full; + video.fromUser = AppUsersManager.getUser(video.user_id); + + return video; + } + + function openVideo (videoID, accessHash) { + var scope = $rootScope.$new(true); + scope.videoID = videoID; + scope.progress = {enabled: false}; + scope.player = {}; + scope.close = function () { + modalInstance.close(); + } + + var modalInstance = $modal.open({ + templateUrl: 'partials/video_modal.html', + controller: 'VideoModalController', + scope: scope + }); + } + + $rootScope.openVideo = openVideo; + + return { + saveVideo: saveVideo, + wrapForHistory: wrapForHistory, + wrapForFull: wrapForFull, + openVideo: openVideo + } +}) + +.service('AppDocsManager', function ($rootScope, $modal, $window, $timeout, MtpApiFileManager, AppUsersManager) { + var docs = {}; + + function saveDoc (apiDoc) { + docs[apiDoc.id] = apiDoc; + + if (apiDoc.thumb && apiDoc.thumb._ == 'photoCachedSize') { + MtpApiFileManager.saveSmallFile(apiDoc.thumb.location, apiDoc.thumb.bytes); + + // Memory + apiDoc.thumb.size = apiDoc.thumb.bytes.length; + delete apiDoc.thumb.bytes; + apiDoc.thumb._ = 'photoSize'; + } + }; + + function wrapForHistory (docID) { + var doc = angular.copy(docs[docID]), + width = 100, + height = 100, + thumbPhotoSize = doc.thumb, + thumb = { + placeholder: 'img/placeholders/DocThumbConversation.jpg', + width: width, + height: height + }; + + if (thumbPhotoSize && thumbPhotoSize._ != 'photoSizeEmpty') { + if (thumbPhotoSize.w > thumbPhotoSize.h) { + thumb.height = parseInt(thumbPhotoSize.h * width / thumbPhotoSize.w); + } else { + thumb.width = parseInt(thumbPhotoSize.w * height / thumbPhotoSize.h); + } + + thumb.location = thumbPhotoSize.location; + thumb.size = thumbPhotoSize.size; + } + + doc.thumb = thumb; + + return doc; + } + + function openDoc (docID, accessHash) { + var doc = docs[docID], + inputFileLocation = { + _: 'inputDocumentFileLocation', + id: docID, + access_hash: accessHash || doc.access_hash + }, + scope = {}; + + scope.progress = {enabled: true, percent: 1}; + + + if (window.chrome && chrome.fileSystem && chrome.fileSystem.chooseEntry) { + var ext = (doc.file_name.split('.', 2) || [])[1] || '', + mime = doc.mime_type; + chrome.fileSystem.chooseEntry({ + type: 'saveFile', + suggestedName: doc.file_name, + accepts: [{ + mimeTypes: [mime], + extensions: [ext] + }] + }, function (writableFileEntry) { + MtpApiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size, writableFileEntry).then(function (url) { + dLog('file save done'); + }); + + }); + } else { + MtpApiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size).then(function (url) { + scope.progress.enabled = false; + + var a = $('Download').attr('href', url).attr('target', '_blank').attr('download', doc.file_name).appendTo('body'); + a[0].dataset.downloadurl = ['png', doc.file_name, url].join(':'); + a[0].click(); + $timeout(function () { + a.remove(); + }, 100); + }, function (e) { + dLog('document download failed', e); + }, function (progress) { + scope.progress.percent = Math.max(1, Math.floor(100 * progress.done / progress.total)); + }); + } + } + + $rootScope.openDoc = openDoc; + + return { + saveDoc: saveDoc, + wrapForHistory: wrapForHistory, + openDoc: openDoc + } +}) + +.service('ExternalResourcesManager', function ($q, $http) { + var urlPromises = {}; + + function downloadImage (url) { + if (urlPromises[url] !== undefined) { + return urlPromises[url]; + } + + var deferred = $q.defer(); + + $http.get(url, {responseType: 'blob', transformRequest: null}) + .then( + function (response) { + deferred.resolve(window.webkitURL.createObjectURL(response.data)); + }, function (error) { + deferred.reject(error); + } + ); + + return urlPromises[url] = deferred.promise; + } + + return { + downloadImage: downloadImage + } +}) + + +.service('ApiUpdatesManager', function ($rootScope, MtpNetworkerFactory, AppUsersManager, AppChatsManager, AppPeersManager, MtpApiManager) { + + var curState = {invalid: true}; + + function processUpdateMessage (updateMessage) { + if (curState.invalid) { + return false; + } + + if (updateMessage.seq) { + if (!saveSeq(updateMessage.seq, updateMessage.seq_start)) { + return false; + } + if (updateMessage.date) { + curState.date = updateMessage.date; + } + } + + + switch (updateMessage._) { + case 'updatesTooLong': + getDifference(); + break; + + case 'updateShort': + saveUpdate(updateMessage.update); + break; + + case 'updatesCombined': + case 'updates': + AppUsersManager.saveApiUsers(updateMessage.users); + AppChatsManager.saveApiChats(updateMessage.chats); + + angular.forEach(updateMessage.updates, function (update) { + saveUpdate(update); + }); + break; + + case 'updateShortMessage': + var fromUser = AppUsersManager.getUser(updateMessage.from_id); + if (!fromUser || fromUser.deleted) { + getDifference(); + break; + } + saveUpdate({ + _: 'updateNewMessage', + message: { + _: 'message', + id: updateMessage.id, + from_id: updateMessage.from_id, + to_id: AppPeersManager.getOutputPeer(MtpApiManager.getUserID()), + out: false, + unread: true, + date: updateMessage.date, + message: updateMessage.message, + media: {_: 'messageMediaEmpty'} + }, + pts: updateMessage.pts + }); + break; + + case 'updateShortChatMessage': + var fromUser = AppUsersManager.getUser(updateMessage.from_id), + chat = AppChatsManager.getChat(updateMessage.chat_id); + + if (!fromUser || fromUser.deleted || !chat || chat.deleted) { + getDifference(); + break; + } + saveUpdate({ + _: 'updateNewMessage', + message: { + _: 'message', + id: updateMessage.id, + from_id: updateMessage.from_id, + to_id: AppPeersManager.getOutputPeer(-updateMessage.chat_id), + out: false, + unread: true, + date: updateMessage.date, + message: updateMessage.message, + media: {_: 'messageMediaEmpty'} + }, + pts: updateMessage.pts + }); + break; + } + } + + function getDifference (force) { + if (curState.invalid && !force) { + return false; + } + + curState.invalid = true; + MtpApiManager.invokeApi('updates.getDifference', {pts: curState.pts, date: curState.date, qts: 0}).then(function (differenceResult) { + if (differenceResult._ == 'updates.differenceEmpty') { + curState.date = differenceResult.date; + curState.seq = differenceResult.seq; + delete curState.invalid; + return false; + } + + AppUsersManager.saveApiUsers(differenceResult.users); + AppChatsManager.saveApiChats(differenceResult.chats); + + angular.forEach(differenceResult.new_messages, function (apiMessage) { + saveUpdate({ + _: 'updateNewMessage', + message: apiMessage, + pts: curState.pts + }, true); + }); + + angular.forEach(differenceResult.other_updates, function(update){ + saveUpdate(update, true); + }); + + var nextState = differenceResult.intermediate_state || differenceResult.state; + curState.seq = nextState.seq; + curState.pts = nextState.pts; + curState.date = nextState.date; + + if (differenceResult._ == 'updates.differenceSlice') { + getDifference(true); + } else { + delete curState.invalid; + } + }); + } + + function saveUpdate (update, force) { + if (curState.invalid && !force) { + return false; + } + if (update.pts) { + curState.pts = update.pts; + } + + $rootScope.$broadcast('apiUpdate', update); + } + + function saveSeq (seq, seqStart) { + // dLog('saving seq', curState.invalid, seq, seqStart, curState.seq); + + if (curState.invalid) { + return false; + } + + seqStart = seqStart || seq; + + if (seqStart != curState.seq + 1) { + // dLog('seq hole', seqStart, curState.seq); + if (seqStart != curState.seq) { + getDifference(); + } + return false; + } + + curState.seq = seq; + + return true; + } + + function attach () { + MtpNetworkerFactory.setUpdatesProcessor(processUpdateMessage); + MtpApiManager.invokeApi('updates.getState').then(function (stateResult) { + curState.seq = stateResult.seq; + curState.pts = stateResult.pts; + curState.date = stateResult.date; + delete curState.invalid; + }) + } + + + return { + saveUpdate: saveUpdate, + saveSeq: saveSeq, + attach: attach + } +}) + +.service('RichTextProcessor', function ($sce, $sanitize) { + + var emojiUtf = [], + emojiMap = {}, + emojiData = Config.Emoji, + emojiCode; + + for (emojiCode in emojiData) { + emojiUtf.push(emojiData[emojiCode][0]); + emojiMap[emojiData[emojiCode][0]] = emojiCode; + } + + var regExp = new RegExp('((?:(ftp|https?)://|(?:mailto:)?([A-Za-z0-9._%+-]+@))(\\S*\\.\\S*[^\\s.;,(){}<>"\']))|(\\n)|(' + emojiUtf.join('|') + ')', 'i'); + + // dLog(regExp); + + + return { + wrapRichText: wrapRichText + }; + + function encodeEntities(value) { + return value. + replace(/&/g, '&'). + replace(/([^\#-~| |!])/g, function (value) { // non-alphanumeric + return '&#' + value.charCodeAt(0) + ';'; + }). + replace(//g, '>'); + }; + + + function wrapRichText(text, options) { + if (!text || !text.length) { + return ''; + } + + options = options || {}; + + text = text.replace(/\ufe0f/g, '', text); + + var match, + raw = text, + html = [], + url, + emojiTitle, + emojiFound = false; + + + while ((match = raw.match(regExp))) { + // dLog(2, match); + html.push(encodeEntities(raw.substr(0, match.index))); + + if (match[1]) { // URL + if (!options.noLinks) { + if (match[3]) { + html.push( + '', + encodeEntities(match[3] + match[4]), + '' + ); + } else { + html.push( + '', + encodeEntities((match[2] != 'http' ? match[2] + '://' : '') + match[4]), + '' + ); + } + } else { + html.push(encodeEntities(match[0])); + } + } + else if (match[5]) { // New line + if (!options.noLinebreaks) { + html.push('
'); + } else { + html.push(' '); + } + } + else if (match[6]) { + + if (emojiCode = emojiMap[match[6]]) { + emojiFound = true; + emojiTitle = encodeEntities(emojiData[emojiCode][1][0]); + html.push( + ':', + emojiTitle, + ':' + ); + } else { + html.push(encodeEntities(match[6])); + } + } + raw = raw.substr(match.index + match[0].length); + } + + html.push(encodeEntities(raw)); + + text = $sanitize(html.join('')); + + // dLog(3, text, html); + + if (emojiFound) { + text = text.replace(//g, + ''); + } + + // dLog(4, text, html); + + return $sce.trustAs('html', text); + } + +}) diff --git a/app/js/util.js b/app/js/util.js new file mode 100644 index 00000000..e65c18d5 --- /dev/null +++ b/app/js/util.js @@ -0,0 +1,55 @@ +/*! + * Webogram v0.1 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +function checkClick (e, noprevent) { + if (e.which == 1 && (e.ctrlKey || e.metaKey) || e.which == 2) { + return true; + } + + if (!noprevent) { + e.preventDefault(); + } + + return false; +} + +function checkDragEvent(e) { + if (!e || e.target && (e.target.tagName == 'IMG' || e.target.tagName == 'A')) return false; + if (e.dataTransfer && e.dataTransfer.types) { + for (var i = 0; i < e.dataTransfer.types.length; i++) { + if (e.dataTransfer.types[i] == 'Files') { + return true; + } + } + } else { + return true; + } + + return false; +} + +function cancelEvent (event) { + event = event || window.event; + + event.stopPropagation && event.stopPropagation(); + event.preventDefault && event.preventDefault(); + + return false; +} + +function onCtrlEnter (textarea, cb) { + $(textarea).on('keydown', function (e) { + if (e.keyCode == 13 && (e.ctrlKey || e.metaKey)) { + cb(); + return cancelEvent(e); + } + }); +} + +function onContentLoaded (cb) { + setTimeout(cb, 0); +}; \ No newline at end of file diff --git a/app/manifest.json b/app/manifest.json new file mode 100644 index 00000000..7a13a6bb --- /dev/null +++ b/app/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "Telegram UNOFFICIAL", + "version": "0.0.9", + "short_name": "Webogram", + "manifest_version": 2, + "app": { + "background": { + "scripts": ["vendor/angular/angular.js", "js/background.js"] + } + }, + "permissions": [ + "webview", + {"fileSystem": ["write"]}, + "storage" + ], + "icons": { "16": "img/icons/icon16.png", + "128": "img/icons/icon128.png" } +} \ No newline at end of file diff --git a/app/partials/chat_modal.html b/app/partials/chat_modal.html new file mode 100644 index 00000000..60855a4d --- /dev/null +++ b/app/partials/chat_modal.html @@ -0,0 +1,41 @@ +
+ + + + + +
\ No newline at end of file diff --git a/app/partials/dialog.html b/app/partials/dialog.html new file mode 100644 index 00000000..e81014e9 --- /dev/null +++ b/app/partials/dialog.html @@ -0,0 +1,73 @@ + + +
+
+ {{dialogMessage.date | dateOrTime}} +
+ + {{dialogMessage.unreadCount}} + +
+ +
+ +
+ +
+ +
+ + + + +
+ +
+ + You{{((dialogMessage.out || dialogMessage.peerID < 0) && (dialogMessage.message.length || dialogMessage.media && dialogMessage.media._ != 'messageMediaEmpty')) ? ':' : ''}} + + + + + Photo + + + Video + + + Document + + + Location + + + Contact + + + + + + created the group + + + changed group name + + + changed group photo + + + removed group photo + + + invited + + + kicked + + + + +
+ +
+
diff --git a/app/partials/head.html b/app/partials/head.html new file mode 100644 index 00000000..66c5f874 --- /dev/null +++ b/app/partials/head.html @@ -0,0 +1,17 @@ +
+ +
\ No newline at end of file diff --git a/app/partials/im.html b/app/partials/im.html new file mode 100644 index 00000000..c9bf9224 --- /dev/null +++ b/app/partials/im.html @@ -0,0 +1,118 @@ +
+ +
+ +
+ +
+ +
+
+
+ +
+
+
+
+ +
+
No history to display
+ +
+
+ +
+ +
+
+ +
+

+ + + + + + +

+
+ +
+

+ + + {{historyPeer.data | userStatus}} +

+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+
+ is typing.. +
+
+ +
+ +
+ +
+ +
+
+ + +
+
+ +
+
+ +
+
+
Drop photos here to send
+ + +
+ +
+ +
+ + +
+ + +
+
+ +
+
+ +
+ +
+ + +
+ diff --git a/app/partials/login.html b/app/partials/login.html new file mode 100644 index 00000000..0b616d4c --- /dev/null +++ b/app/partials/login.html @@ -0,0 +1,28 @@ +
+ + + \ No newline at end of file diff --git a/app/partials/message.html b/app/partials/message.html new file mode 100644 index 00000000..b5b832f4 --- /dev/null +++ b/app/partials/message.html @@ -0,0 +1,91 @@ +
+ +
+
+ + + + + + created the group «{{historyMessage.action.title}}» + + + changed group name to «{{historyMessage.action.title}}» + + + changed group photo + + + removed group photo + + + invited + + + kicked + + + + unsupported action {{historyMessage.action}} + + + +
+ + + + + +
+ +
+ + + + +
+ + {{historyMessage.date | dateOrTime}} +
+ +
+ +
+ +
+ + + + + + + +
+ {{historyMessage.media.video.duration | duration}} + +
+
+ + + +
{{historyMessage.media.document.file_name}} {{historyMessage.media.document.size | formatSize}}
+
+ + + + + +
+ + + +
{{historyMessage.media.first_name}} {{historyMessage.media.last_name}}
+
{{historyMessage.media.phone_number}}
+
+
+ +
+
+ +
+
diff --git a/app/partials/photo_modal.html b/app/partials/photo_modal.html new file mode 100644 index 00000000..02876897 --- /dev/null +++ b/app/partials/photo_modal.html @@ -0,0 +1,11 @@ +
+ + + +
\ No newline at end of file diff --git a/app/partials/user_modal.html b/app/partials/user_modal.html new file mode 100644 index 00000000..543c9d3c --- /dev/null +++ b/app/partials/user_modal.html @@ -0,0 +1,25 @@ +
+ + + + + + +
\ No newline at end of file diff --git a/app/partials/video_modal.html b/app/partials/video_modal.html new file mode 100644 index 00000000..3916660c --- /dev/null +++ b/app/partials/video_modal.html @@ -0,0 +1,11 @@ +
+ + + +
\ No newline at end of file diff --git a/app/partials/welcome.html b/app/partials/welcome.html new file mode 100644 index 00000000..7396c588 --- /dev/null +++ b/app/partials/welcome.html @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/app/vendor/README.md b/app/vendor/README.md new file mode 100644 index 00000000..07a91dcb --- /dev/null +++ b/app/vendor/README.md @@ -0,0 +1,70 @@ +## Third party libraries + +### [AngularJS](http://angularjs.org/) +**Author**: Google, Inc. +License - MIT, https://github.com/angular/angular.js/blob/master/LICENSE + +### [JSBN](http://www-cs-students.stanford.edu/~tjw/jsbn/) +**Author**: Tom Wu +**License**: BSD, http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE + +Biginteger for RSA, PQ prime factorization + + +### [jQuery Emojiarea](https://github.com/diy/jquery-emojiarea) +**Author**: diy +**License**: Apache, Version 2.0, https://github.com/diy/jquery-emojiarea#license + +Emoji keyboard and rich-textfield for composing messages with emoticons + + +### [UI Bootstrap](http://angular-ui.github.io/bootstrap/) +**Author**: AngularUI Team, https://github.com/organizations/angular-ui/teams/291112 +**License**: MIT, https://github.com/angular-ui/bootstrap/blob/master/LICENSE + +Modal windows + + +### [jQuery](https://github.com/jquery/jquery) +**Author**: jQuery Foundation and other contributors +**License**: MIT, https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt + +Dom manupulations. + +### [Bootstrap](https://github.com/twbs/bootstrap) +**Author**: Twitter, Inc +**License**: MIT, https://github.com/twbs/bootstrap/blob/master/LICENSE + +Normalize, CSS-framework + +### [nanoScrollerJS](https://github.com/jamesflorentino/nanoScrollerJS) +**Author**: James Florentino +**License**: MIT, https://github.com/jamesflorentino/nanoScrollerJS/blob/master/LICENSE-MIT + +Beautiful OS X Lion-like scrollbars + + +### [CryptoJS](https://code.google.com/p/crypto-js/) +**Author**: Jeff Mott +**License**: BSD-3-Clause, https://code.google.com/p/crypto-js/wiki/License + +AES, SHA-1 implementation + +### [zlib.js](https://github.com/imaya/zlib.js) +**Author**: imaya +**License**: MIT, https://github.com/imaya/zlib.js/blob/master/LICENSE + +GZIP for decompressing server responses + +### [emoji-data](https://github.com/iamcal/emoji-data) +**Author**: iamcal +**License**: not specified + +Build emoji list in apropriate format. Generate sheet in future, when needed. + + +### [gemoji](https://github.com/github/gemoji) +**Author**: GitHub Inc, 37signals, id Software, whynne@deviantart, Apple Inc. +**License**: https://github.com/github/gemoji/blob/master/LICENSE + +Emoji images \ No newline at end of file diff --git a/app/vendor/angular/angular-animate.js b/app/vendor/angular/angular-animate.js new file mode 100644 index 00000000..ce9a2d47 --- /dev/null +++ b/app/vendor/angular/angular-animate.js @@ -0,0 +1,1294 @@ +/** + * @license AngularJS v1.2.3 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular, undefined) {'use strict'; + +/* jshint maxlen: false */ + +/** + * @ngdoc overview + * @name ngAnimate + * @description + * + * # ngAnimate + * + * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives. + * + * {@installModule animate} + * + *
+ * + * # Usage + * + * To see animations in action, all that is required is to define the appropriate CSS classes + * or to register a JavaScript animation via the myModule.animation() function. The directives that support animation automatically are: + * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation + * by using the `$animate` service. + * + * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives: + * + * | Directive | Supported Animations | + * |---------------------------------------------------------- |----------------------------------------------------| + * | {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave and move | + * | {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave | + * | {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave | + * | {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave | + * | {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave | + * | {@link ng.directive:ngClass#usage_animations ngClass} | add and remove | + * | {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) | + * + * You can find out more information about animations upon visiting each directive page. + * + * Below is an example of how to apply animations to a directive that supports animation hooks: + * + *
+ * 
+ *
+ * 
+ * 
+ * 
+ * + * Keep in mind that if an animation is running, any child elements cannot be animated until the parent element's + * animation has completed. + * + *

CSS-defined Animations

+ * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes + * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported + * and can be used to play along with this naming structure. + * + * The following code below demonstrates how to perform animations using **CSS transitions** with Angular: + * + *
+ * 
+ *
+ * 
+ *
+ *
+ *
+ * + * The following code below demonstrates how to perform animations using **CSS animations** with Angular: + * + *
+ * 
+ *
+ * 
+ *
+ *
+ *
+ * + * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing. + * + * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add + * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically + * detect the CSS code to determine when the animation ends. Once the animation is over then both CSS classes will be + * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end + * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element + * has no CSS transition/animation classes applied to it. + * + *

CSS Staggering Animations

+ * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a + * curtain-like effect. The ngAnimate module, as of 1.2.0, supports staggering animations and the stagger effect can be + * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for + * the animation. The style property expected within the stagger class can either be a **transition-delay** or an + * **animation-delay** property (or both if your animation contains both transitions and keyframe animations). + * + *
+ * .my-animation.ng-enter {
+ *   /* standard transition code */
+ *   -webkit-transition: 1s linear all;
+ *   transition: 1s linear all;
+ *   opacity:0;
+ * }
+ * .my-animation.ng-enter-stagger {
+ *   /* this will have a 100ms delay between each successive leave animation */
+ *   -webkit-transition-delay: 0.1s;
+ *   transition-delay: 0.1s;
+ *
+ *   /* in case the stagger doesn't work then these two values
+ *    must be set to 0 to avoid an accidental CSS inheritance */
+ *   -webkit-transition-duration: 0s;
+ *   transition-duration: 0s;
+ * }
+ * .my-animation.ng-enter.ng-enter-active {
+ *   /* standard transition styles */
+ *   opacity:1;
+ * }
+ * 
+ * + * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations + * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this + * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation + * will also be reset if more than 10ms has passed after the last animation has been fired. + * + * The following code will issue the **ng-leave-stagger** event on the element provided: + * + *
+ * var kids = parent.children();
+ *
+ * $animate.leave(kids[0]); //stagger index=0
+ * $animate.leave(kids[1]); //stagger index=1
+ * $animate.leave(kids[2]); //stagger index=2
+ * $animate.leave(kids[3]); //stagger index=3
+ * $animate.leave(kids[4]); //stagger index=4
+ *
+ * $timeout(function() {
+ *   //stagger has reset itself
+ *   $animate.leave(kids[5]); //stagger index=0
+ *   $animate.leave(kids[6]); //stagger index=1
+ * }, 100, false);
+ * 
+ * + * Stagger animations are currently only supported within CSS-defined animations. + * + *

JavaScript-defined Animations

+ * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations on browsers that do not + * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module. + * + *
+ * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application.
+ * var ngModule = angular.module('YourApp', []);
+ * ngModule.animation('.my-crazy-animation', function() {
+ *   return {
+ *     enter: function(element, done) {
+ *       //run the animation here and call done when the animation is complete
+ *       return function(cancelled) {
+ *         //this (optional) function will be called when the animation
+ *         //completes or when the animation is cancelled (the cancelled
+ *         //flag will be set to true if cancelled).
+ *       }
+ *     }
+ *     leave: function(element, done) { },
+ *     move: function(element, done) { },
+ *
+ *     //animation that can be triggered before the class is added
+ *     beforeAddClass: function(element, className, done) { },
+ *
+ *     //animation that can be triggered after the class is added
+ *     addClass: function(element, className, done) { },
+ *
+ *     //animation that can be triggered before the class is removed
+ *     beforeRemoveClass: function(element, className, done) { },
+ *
+ *     //animation that can be triggered after the class is removed
+ *     removeClass: function(element, className, done) { }
+ *   }
+ * });
+ * 
+ * + * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run + * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits + * the element's CSS class attribute value and then run the matching animation event function (if found). + * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function will + * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported). + * + * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned. + * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run, + * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation + * or transition code that is defined via a stylesheet). + * + */ + +angular.module('ngAnimate', ['ng']) + + /** + * @ngdoc object + * @name ngAnimate.$animateProvider + * @description + * + * The `$animateProvider` allows developers to register JavaScript animation event handlers directly inside of a module. + * When an animation is triggered, the $animate service will query the $animate service to find any animations that match + * the provided name value. + * + * Requires the {@link ngAnimate `ngAnimate`} module to be installed. + * + * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application. + * + */ + .config(['$provide', '$animateProvider', function($provide, $animateProvider) { + var noop = angular.noop; + var forEach = angular.forEach; + var selectors = $animateProvider.$$selectors; + + var ELEMENT_NODE = 1; + var NG_ANIMATE_STATE = '$$ngAnimateState'; + var NG_ANIMATE_CLASS_NAME = 'ng-animate'; + var rootAnimateState = {running: true}; + + $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$timeout', '$rootScope', '$document', + function($delegate, $injector, $sniffer, $rootElement, $timeout, $rootScope, $document) { + + $rootElement.data(NG_ANIMATE_STATE, rootAnimateState); + + // disable animations during bootstrap, but once we bootstrapped, wait again + // for another digest until enabling animations. The reason why we digest twice + // is because all structural animations (enter, leave and move) all perform a + // post digest operation before animating. If we only wait for a single digest + // to pass then the structural animation would render its animation on page load. + // (which is what we're trying to avoid when the application first boots up.) + $rootScope.$$postDigest(function() { + $rootScope.$$postDigest(function() { + rootAnimateState.running = false; + }); + }); + + function lookup(name) { + if (name) { + var matches = [], + flagMap = {}, + classes = name.substr(1).split('.'); + + //the empty string value is the default animation + //operation which performs CSS transition and keyframe + //animations sniffing. This is always included for each + //element animation procedure if the browser supports + //transitions and/or keyframe animations + if ($sniffer.transitions || $sniffer.animations) { + classes.push(''); + } + + for(var i=0; i < classes.length; i++) { + var klass = classes[i], + selectorFactoryName = selectors[klass]; + if(selectorFactoryName && !flagMap[klass]) { + matches.push($injector.get(selectorFactoryName)); + flagMap[klass] = true; + } + } + return matches; + } + } + + /** + * @ngdoc object + * @name ngAnimate.$animate + * @function + * + * @description + * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations. + * When any of these operations are run, the $animate service + * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object) + * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run. + * + * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives + * will work out of the box without any extra configuration. + * + * Requires the {@link ngAnimate `ngAnimate`} module to be installed. + * + * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application. + * + */ + return { + /** + * @ngdoc function + * @name ngAnimate.$animate#enter + * @methodOf ngAnimate.$animate + * @function + * + * @description + * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once + * the animation is started, the following CSS classes will be present on the element for the duration of the animation: + * + * Below is a breakdown of each step that occurs during enter animation: + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------|---------------------------------------------| + * | 1. $animate.enter(...) is called | class="my-animation" | + * | 2. element is inserted into the parentElement element or beside the afterElement element | class="my-animation" | + * | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" | + * | 4. the .ng-enter class is added to the element | class="my-animation ng-animate ng-enter" | + * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-enter" | + * | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-enter" | + * | 7. the .ng-enter-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" | + * | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" | + * | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | + * | 10. The doneCallback() callback is fired (if provided) | class="my-animation" | + * + * @param {jQuery/jqLite element} element the element that will be the focus of the enter animation + * @param {jQuery/jqLite element} parentElement the parent element of the element that will be the focus of the enter animation + * @param {jQuery/jqLite element} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation + * @param {function()=} doneCallback the callback function that will be called once the animation is complete + */ + enter : function(element, parentElement, afterElement, doneCallback) { + this.enabled(false, element); + $delegate.enter(element, parentElement, afterElement); + $rootScope.$$postDigest(function() { + performAnimation('enter', 'ng-enter', element, parentElement, afterElement, noop, doneCallback); + }); + }, + + /** + * @ngdoc function + * @name ngAnimate.$animate#leave + * @methodOf ngAnimate.$animate + * @function + * + * @description + * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once + * the animation is started, the following CSS classes will be added for the duration of the animation: + * + * Below is a breakdown of each step that occurs during enter animation: + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------|---------------------------------------------| + * | 1. $animate.leave(...) is called | class="my-animation" | + * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" | + * | 3. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" | + * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" | + * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-leave" | + * | 6. the .ng-leave-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" | + * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" | + * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | + * | 9. The element is removed from the DOM | ... | + * | 10. The doneCallback() callback is fired (if provided) | ... | + * + * @param {jQuery/jqLite element} element the element that will be the focus of the leave animation + * @param {function()=} doneCallback the callback function that will be called once the animation is complete + */ + leave : function(element, doneCallback) { + cancelChildAnimations(element); + this.enabled(false, element); + $rootScope.$$postDigest(function() { + performAnimation('leave', 'ng-leave', element, null, null, function() { + $delegate.leave(element); + }, doneCallback); + }); + }, + + /** + * @ngdoc function + * @name ngAnimate.$animate#move + * @methodOf ngAnimate.$animate + * @function + * + * @description + * Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or + * add the element directly after the afterElement element if present. Then the move animation will be run. Once + * the animation is started, the following CSS classes will be added for the duration of the animation: + * + * Below is a breakdown of each step that occurs during move animation: + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------|---------------------------------------------| + * | 1. $animate.move(...) is called | class="my-animation" | + * | 2. element is moved into the parentElement element or beside the afterElement element | class="my-animation" | + * | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" | + * | 4. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" | + * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" | + * | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-move" | + * | 7. the .ng-move-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" | + * | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" | + * | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | + * | 10. The doneCallback() callback is fired (if provided) | class="my-animation" | + * + * @param {jQuery/jqLite element} element the element that will be the focus of the move animation + * @param {jQuery/jqLite element} parentElement the parentElement element of the element that will be the focus of the move animation + * @param {jQuery/jqLite element} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation + * @param {function()=} doneCallback the callback function that will be called once the animation is complete + */ + move : function(element, parentElement, afterElement, doneCallback) { + cancelChildAnimations(element); + this.enabled(false, element); + $delegate.move(element, parentElement, afterElement); + $rootScope.$$postDigest(function() { + performAnimation('move', 'ng-move', element, parentElement, afterElement, noop, doneCallback); + }); + }, + + /** + * @ngdoc function + * @name ngAnimate.$animate#addClass + * @methodOf ngAnimate.$animate + * + * @description + * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class. + * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide + * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions + * or keyframes are defined on the -add or base CSS class). + * + * Below is a breakdown of each step that occurs during addClass animation: + * + * | Animation Step | What the element class attribute looks like | + * |------------------------------------------------------------------------------------------------|---------------------------------------------| + * | 1. $animate.addClass(element, 'super') is called | class="my-animation" | + * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" | + * | 3. the .super-add class are added to the element | class="my-animation ng-animate super-add" | + * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-add" | + * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate super-add" | + * | 6. the .super, .super-add-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super super-add super-add-active" | + * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation super-add super-add-active" | + * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" | + * | 9. The super class is kept on the element | class="my-animation super" | + * | 10. The doneCallback() callback is fired (if provided) | class="my-animation super" | + * + * @param {jQuery/jqLite element} element the element that will be animated + * @param {string} className the CSS class that will be added to the element and then animated + * @param {function()=} doneCallback the callback function that will be called once the animation is complete + */ + addClass : function(element, className, doneCallback) { + performAnimation('addClass', className, element, null, null, function() { + $delegate.addClass(element, className); + }, doneCallback); + }, + + /** + * @ngdoc function + * @name ngAnimate.$animate#removeClass + * @methodOf ngAnimate.$animate + * + * @description + * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value + * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in + * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if + * no CSS transitions or keyframes are defined on the -remove or base CSS classes). + * + * Below is a breakdown of each step that occurs during removeClass animation: + * + * | Animation Step | What the element class attribute looks like | + * |-----------------------------------------------------------------------------------------------|---------------------------------------------| + * | 1. $animate.removeClass(element, 'super') is called | class="my-animation super" | + * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation super ng-animate" | + * | 3. the .super-remove class are added to the element | class="my-animation super ng-animate super-remove"| + * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" | + * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation super ng-animate super-remove" | + * | 6. the .super-remove-active and .ng-animate-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" | + * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" | + * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | + * | 9. The doneCallback() callback is fired (if provided) | class="my-animation" | + * + * + * @param {jQuery/jqLite element} element the element that will be animated + * @param {string} className the CSS class that will be animated and then removed from the element + * @param {function()=} doneCallback the callback function that will be called once the animation is complete + */ + removeClass : function(element, className, doneCallback) { + performAnimation('removeClass', className, element, null, null, function() { + $delegate.removeClass(element, className); + }, doneCallback); + }, + + /** + * @ngdoc function + * @name ngAnimate.$animate#enabled + * @methodOf ngAnimate.$animate + * @function + * + * @param {boolean=} value If provided then set the animation on or off. + * @param {jQuery/jqLite element=} element If provided then the element will be used to represent the enable/disable operation + * @return {boolean} Current animation state. + * + * @description + * Globally enables/disables animations. + * + */ + enabled : function(value, element) { + switch(arguments.length) { + case 2: + if(value) { + cleanup(element); + } else { + var data = element.data(NG_ANIMATE_STATE) || {}; + data.disabled = true; + element.data(NG_ANIMATE_STATE, data); + } + break; + + case 1: + rootAnimateState.disabled = !value; + break; + + default: + value = !rootAnimateState.disabled; + break; + } + return !!value; + } + }; + + /* + all animations call this shared animation triggering function internally. + The animationEvent variable refers to the JavaScript animation event that will be triggered + and the className value is the name of the animation that will be applied within the + CSS code. Element, parentElement and afterElement are provided DOM elements for the animation + and the onComplete callback will be fired once the animation is fully complete. + */ + function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) { + var currentClassName = element.attr('class') || ''; + var classes = currentClassName + ' ' + className; + var animationLookup = (' ' + classes).replace(/\s+/g,'.'); + if (!parentElement) { + parentElement = afterElement ? afterElement.parent() : element.parent(); + } + + var matches = lookup(animationLookup); + var isClassBased = animationEvent == 'addClass' || animationEvent == 'removeClass'; + var ngAnimateState = element.data(NG_ANIMATE_STATE) || {}; + + //skip the animation if animations are disabled, a parent is already being animated, + //the element is not currently attached to the document body or then completely close + //the animation if any matching animations are not found at all. + //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case a NO animation is not found. + if (animationsDisabled(element, parentElement) || matches.length === 0) { + fireDOMOperation(); + closeAnimation(); + return; + } + + var animations = []; + //only add animations if the currently running animation is not structural + //or if there is no animation running at all + if(!ngAnimateState.running || !(isClassBased && ngAnimateState.structural)) { + forEach(matches, function(animation) { + //add the animation to the queue to if it is allowed to be cancelled + if(!animation.allowCancel || animation.allowCancel(element, animationEvent, className)) { + var beforeFn, afterFn = animation[animationEvent]; + + //Special case for a leave animation since there is no point in performing an + //animation on a element node that has already been removed from the DOM + if(animationEvent == 'leave') { + beforeFn = afterFn; + afterFn = null; //this must be falsy so that the animation is skipped for leave + } else { + beforeFn = animation['before' + animationEvent.charAt(0).toUpperCase() + animationEvent.substr(1)]; + } + animations.push({ + before : beforeFn, + after : afterFn + }); + } + }); + } + + //this would mean that an animation was not allowed so let the existing + //animation do it's thing and close this one early + if(animations.length === 0) { + fireDOMOperation(); + fireDoneCallbackAsync(); + return; + } + + //this value will be searched for class-based CSS className lookup. Therefore, + //we prefix and suffix the current className value with spaces to avoid substring + //lookups of className tokens + var futureClassName = ' ' + currentClassName + ' '; + if(ngAnimateState.running) { + //if an animation is currently running on the element then lets take the steps + //to cancel that animation and fire any required callbacks + $timeout.cancel(ngAnimateState.closeAnimationTimeout); + cleanup(element); + cancelAnimations(ngAnimateState.animations); + + //if the class is removed during the reflow then it will revert the styles temporarily + //back to the base class CSS styling causing a jump-like effect to occur. This check + //here ensures that the domOperation is only performed after the reflow has commenced + if(ngAnimateState.beforeComplete) { + (ngAnimateState.done || noop)(true); + } else if(isClassBased && !ngAnimateState.structural) { + //class-based animations will compare element className values after cancelling the + //previous animation to see if the element properties already contain the final CSS + //class and if so then the animation will be skipped. Since the domOperation will + //be performed only after the reflow is complete then our element's className value + //will be invalid. Therefore the same string manipulation that would occur within the + //DOM operation will be performed below so that the class comparison is valid... + futureClassName = ngAnimateState.event == 'removeClass' ? + futureClassName.replace(ngAnimateState.className, '') : + futureClassName + ngAnimateState.className + ' '; + } + } + + //There is no point in perform a class-based animation if the element already contains + //(on addClass) or doesn't contain (on removeClass) the className being animated. + //The reason why this is being called after the previous animations are cancelled + //is so that the CSS classes present on the element can be properly examined. + var classNameToken = ' ' + className + ' '; + if((animationEvent == 'addClass' && futureClassName.indexOf(classNameToken) >= 0) || + (animationEvent == 'removeClass' && futureClassName.indexOf(classNameToken) == -1)) { + fireDOMOperation(); + fireDoneCallbackAsync(); + return; + } + + //the ng-animate class does nothing, but it's here to allow for + //parent animations to find and cancel child animations when needed + element.addClass(NG_ANIMATE_CLASS_NAME); + + element.data(NG_ANIMATE_STATE, { + running:true, + event:animationEvent, + className:className, + structural:!isClassBased, + animations:animations, + done:onBeforeAnimationsComplete + }); + + //first we run the before animations and when all of those are complete + //then we perform the DOM operation and run the next set of animations + invokeRegisteredAnimationFns(animations, 'before', onBeforeAnimationsComplete); + + function onBeforeAnimationsComplete(cancelled) { + fireDOMOperation(); + if(cancelled === true) { + closeAnimation(); + return; + } + + //set the done function to the final done function + //so that the DOM event won't be executed twice by accident + //if the after animation is cancelled as well + var data = element.data(NG_ANIMATE_STATE); + if(data) { + data.done = closeAnimation; + element.data(NG_ANIMATE_STATE, data); + } + invokeRegisteredAnimationFns(animations, 'after', closeAnimation); + } + + function invokeRegisteredAnimationFns(animations, phase, allAnimationFnsComplete) { + var endFnName = phase + 'End'; + forEach(animations, function(animation, index) { + var animationPhaseCompleted = function() { + progress(index, phase); + }; + + //there are no before functions for enter + move since the DOM + //operations happen before the performAnimation method fires + if(phase == 'before' && (animationEvent == 'enter' || animationEvent == 'move')) { + animationPhaseCompleted(); + return; + } + + if(animation[phase]) { + animation[endFnName] = isClassBased ? + animation[phase](element, className, animationPhaseCompleted) : + animation[phase](element, animationPhaseCompleted); + } else { + animationPhaseCompleted(); + } + }); + + function progress(index, phase) { + var phaseCompletionFlag = phase + 'Complete'; + var currentAnimation = animations[index]; + currentAnimation[phaseCompletionFlag] = true; + (currentAnimation[endFnName] || noop)(); + + for(var i=0;i 0) { + aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1; + } + + animationDuration = Math.max(aDuration, animationDuration); + } + }); + data = { + total : 0, + transitionPropertyStyle: transitionPropertyStyle, + transitionDurationStyle: transitionDurationStyle, + transitionDelayStyle: transitionDelayStyle, + transitionDelay: transitionDelay, + transitionDuration: transitionDuration, + animationDelayStyle: animationDelayStyle, + animationDelay: animationDelay, + animationDuration: animationDuration + }; + if(cacheKey) { + lookupCache[cacheKey] = data; + } + } + return data; + } + + function parseMaxTime(str) { + var maxValue = 0; + var values = angular.isString(str) ? + str.split(/\s*,\s*/) : + []; + forEach(values, function(value) { + maxValue = Math.max(parseFloat(value) || 0, maxValue); + }); + return maxValue; + } + + function getCacheKey(element) { + var parentElement = element.parent(); + var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY); + if(!parentID) { + parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter); + parentID = parentCounter; + } + return parentID + '-' + element[0].className; + } + + function animateSetup(element, className) { + var cacheKey = getCacheKey(element); + var eventCacheKey = cacheKey + ' ' + className; + var stagger = {}; + var ii = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0; + + if(ii > 0) { + var staggerClassName = className + '-stagger'; + var staggerCacheKey = cacheKey + ' ' + staggerClassName; + var applyClasses = !lookupCache[staggerCacheKey]; + + applyClasses && element.addClass(staggerClassName); + + stagger = getElementAnimationDetails(element, staggerCacheKey); + + applyClasses && element.removeClass(staggerClassName); + } + + element.addClass(className); + + var timings = getElementAnimationDetails(element, eventCacheKey); + + /* there is no point in performing a reflow if the animation + timeout is empty (this would cause a flicker bug normally + in the page. There is also no point in performing an animation + that only has a delay and no duration */ + var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration); + if(maxDuration === 0) { + element.removeClass(className); + return false; + } + + var node = element[0]; + //temporarily disable the transition so that the enter styles + //don't animate twice (this is here to avoid a bug in Chrome/FF). + var activeClassName = ''; + if(timings.transitionDuration > 0) { + element.addClass(NG_ANIMATE_FALLBACK_CLASS_NAME); + activeClassName += NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME + ' '; + blockTransitions(element); + } else { + blockKeyframeAnimations(element); + } + + forEach(className.split(' '), function(klass, i) { + activeClassName += (i > 0 ? ' ' : '') + klass + '-active'; + }); + + element.data(NG_ANIMATE_CSS_DATA_KEY, { + className : className, + activeClassName : activeClassName, + maxDuration : maxDuration, + classes : className + ' ' + activeClassName, + timings : timings, + stagger : stagger, + ii : ii + }); + + return true; + } + + function blockTransitions(element) { + element[0].style[TRANSITION_PROP + PROPERTY_KEY] = 'none'; + } + + function blockKeyframeAnimations(element) { + element[0].style[ANIMATION_PROP] = 'none 0s'; + } + + function unblockTransitions(element) { + var node = element[0], prop = TRANSITION_PROP + PROPERTY_KEY; + if(node.style[prop] && node.style[prop].length > 0) { + node.style[prop] = ''; + } + } + + function unblockKeyframeAnimations(element) { + var node = element[0], prop = ANIMATION_PROP; + if(node.style[prop] && node.style[prop].length > 0) { + element[0].style[prop] = ''; + } + } + + function animateRun(element, className, activeAnimationComplete) { + var data = element.data(NG_ANIMATE_CSS_DATA_KEY); + if(!element.hasClass(className) || !data) { + activeAnimationComplete(); + return; + } + + var node = element[0]; + var timings = data.timings; + var stagger = data.stagger; + var maxDuration = data.maxDuration; + var activeClassName = data.activeClassName; + var maxDelayTime = Math.max(timings.transitionDelay, timings.animationDelay) * 1000; + var startTime = Date.now(); + var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT; + var ii = data.ii; + + var applyFallbackStyle, style = '', appliedStyles = []; + if(timings.transitionDuration > 0) { + var propertyStyle = timings.transitionPropertyStyle; + if(propertyStyle.indexOf('all') == -1) { + applyFallbackStyle = true; + var fallbackProperty = $sniffer.msie ? '-ms-zoom' : 'border-spacing'; + style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ', ' + fallbackProperty + '; '; + style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ', ' + timings.transitionDuration + 's; '; + appliedStyles.push(CSS_PREFIX + 'transition-property'); + appliedStyles.push(CSS_PREFIX + 'transition-duration'); + } + } + + if(ii > 0) { + if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) { + var delayStyle = timings.transitionDelayStyle; + if(applyFallbackStyle) { + delayStyle += ', ' + timings.transitionDelay + 's'; + } + + style += CSS_PREFIX + 'transition-delay: ' + + prepareStaggerDelay(delayStyle, stagger.transitionDelay, ii) + '; '; + appliedStyles.push(CSS_PREFIX + 'transition-delay'); + } + + if(stagger.animationDelay > 0 && stagger.animationDuration === 0) { + style += CSS_PREFIX + 'animation-delay: ' + + prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, ii) + '; '; + appliedStyles.push(CSS_PREFIX + 'animation-delay'); + } + } + + if(appliedStyles.length > 0) { + var oldStyle = node.getAttribute('style') || ''; + node.setAttribute('style', oldStyle + ' ' + style); + } + + element.on(css3AnimationEvents, onAnimationProgress); + element.addClass(activeClassName); + + // This will automatically be called by $animate so + // there is no need to attach this internally to the + // timeout done method. + return function onEnd(cancelled) { + element.off(css3AnimationEvents, onAnimationProgress); + element.removeClass(activeClassName); + animateClose(element, className); + for (var i in appliedStyles) { + node.style.removeProperty(appliedStyles[i]); + } + }; + + function onAnimationProgress(event) { + event.stopPropagation(); + var ev = event.originalEvent || event; + var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now(); + /* $manualTimeStamp is a mocked timeStamp value which is set + * within browserTrigger(). This is only here so that tests can + * mock animations properly. Real events fallback to event.timeStamp, + * or, if they don't, then a timeStamp is automatically created for them. + * We're checking to see if the timeStamp surpasses the expected delay, + * but we're using elapsedTime instead of the timeStamp on the 2nd + * pre-condition since animations sometimes close off early */ + if(Math.max(timeStamp - startTime, 0) >= maxDelayTime && ev.elapsedTime >= maxDuration) { + activeAnimationComplete(); + } + } + } + + function prepareStaggerDelay(delayStyle, staggerDelay, index) { + var style = ''; + forEach(delayStyle.split(','), function(val, i) { + style += (i > 0 ? ',' : '') + + (index * staggerDelay + parseInt(val, 10)) + 's'; + }); + return style; + } + + function animateBefore(element, className) { + if(animateSetup(element, className)) { + return function(cancelled) { + cancelled && animateClose(element, className); + }; + } + } + + function animateAfter(element, className, afterAnimationComplete) { + if(element.data(NG_ANIMATE_CSS_DATA_KEY)) { + return animateRun(element, className, afterAnimationComplete); + } else { + animateClose(element, className); + afterAnimationComplete(); + } + } + + function animate(element, className, animationComplete) { + //If the animateSetup function doesn't bother returning a + //cancellation function then it means that there is no animation + //to perform at all + var preReflowCancellation = animateBefore(element, className); + if(!preReflowCancellation) { + animationComplete(); + return; + } + + //There are two cancellation functions: one is before the first + //reflow animation and the second is during the active state + //animation. The first function will take care of removing the + //data from the element which will not make the 2nd animation + //happen in the first place + var cancel = preReflowCancellation; + afterReflow(function() { + unblockTransitions(element); + unblockKeyframeAnimations(element); + //once the reflow is complete then we point cancel to + //the new cancellation function which will remove all of the + //animation properties from the active animation + cancel = animateAfter(element, className, animationComplete); + }); + + return function(cancelled) { + (cancel || noop)(cancelled); + }; + } + + function animateClose(element, className) { + element.removeClass(className); + element.removeClass(NG_ANIMATE_FALLBACK_CLASS_NAME); + element.removeData(NG_ANIMATE_CSS_DATA_KEY); + } + + return { + allowCancel : function(element, animationEvent, className) { + //always cancel the current animation if it is a + //structural animation + var oldClasses = (element.data(NG_ANIMATE_CSS_DATA_KEY) || {}).classes; + if(!oldClasses || ['enter','leave','move'].indexOf(animationEvent) >= 0) { + return true; + } + + var parentElement = element.parent(); + var clone = angular.element(element[0].cloneNode()); + + //make the element super hidden and override any CSS style values + clone.attr('style','position:absolute; top:-9999px; left:-9999px'); + clone.removeAttr('id'); + clone.html(''); + + forEach(oldClasses.split(' '), function(klass) { + clone.removeClass(klass); + }); + + var suffix = animationEvent == 'addClass' ? '-add' : '-remove'; + clone.addClass(suffixClasses(className, suffix)); + parentElement.append(clone); + + var timings = getElementAnimationDetails(clone); + clone.remove(); + + return Math.max(timings.transitionDuration, timings.animationDuration) > 0; + }, + + enter : function(element, animationCompleted) { + return animate(element, 'ng-enter', animationCompleted); + }, + + leave : function(element, animationCompleted) { + return animate(element, 'ng-leave', animationCompleted); + }, + + move : function(element, animationCompleted) { + return animate(element, 'ng-move', animationCompleted); + }, + + beforeAddClass : function(element, className, animationCompleted) { + var cancellationMethod = animateBefore(element, suffixClasses(className, '-add')); + if(cancellationMethod) { + afterReflow(function() { + unblockTransitions(element); + unblockKeyframeAnimations(element); + animationCompleted(); + }); + return cancellationMethod; + } + animationCompleted(); + }, + + addClass : function(element, className, animationCompleted) { + return animateAfter(element, suffixClasses(className, '-add'), animationCompleted); + }, + + beforeRemoveClass : function(element, className, animationCompleted) { + var cancellationMethod = animateBefore(element, suffixClasses(className, '-remove')); + if(cancellationMethod) { + afterReflow(function() { + unblockTransitions(element); + unblockKeyframeAnimations(element); + animationCompleted(); + }); + return cancellationMethod; + } + animationCompleted(); + }, + + removeClass : function(element, className, animationCompleted) { + return animateAfter(element, suffixClasses(className, '-remove'), animationCompleted); + } + }; + + function suffixClasses(classes, suffix) { + var className = ''; + classes = angular.isArray(classes) ? classes : classes.split(/\s+/); + forEach(classes, function(klass, i) { + if(klass && klass.length > 0) { + className += (i > 0 ? ' ' : '') + klass + suffix; + } + }); + return className; + } + }]); + }]); + + +})(window, window.angular); diff --git a/app/vendor/angular/angular-animate.min.js b/app/vendor/angular/angular-animate.min.js new file mode 100644 index 00000000..796fbbb2 --- /dev/null +++ b/app/vendor/angular/angular-animate.min.js @@ -0,0 +1,22 @@ +/* + AngularJS v1.2.3 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(C,k,F){'use strict';k.module("ngAnimate",["ng"]).config(["$provide","$animateProvider",function(M,G){var p=k.noop,r=k.forEach,N=G.$$selectors,T=1,h="$$ngAnimateState",H="ng-animate",l={running:!0};M.decorator("$animate",["$delegate","$injector","$sniffer","$rootElement","$timeout","$rootScope","$document",function(v,C,I,g,s,q,F){function O(a){if(a){var d=[],c={};a=a.substr(1).split(".");(I.transitions||I.animations)&&a.push("");for(var e=0;e=v&&a.elapsedTime>=q&&e()}var n=a.data(y);if(a.hasClass(d)&&n){var l=a[0],g=n.timings,m=n.stagger, +q=n.maxDuration,r=n.activeClassName,v=1E3*Math.max(g.transitionDelay,g.animationDelay),w=Date.now(),t=Q+" "+P,u=n.ii,x,n="",p=[];if(0 + * + * See {@link ngCookies.$cookies `$cookies`} and + * {@link ngCookies.$cookieStore `$cookieStore`} for usage. + */ + + +angular.module('ngCookies', ['ng']). + /** + * @ngdoc object + * @name ngCookies.$cookies + * @requires $browser + * + * @description + * Provides read/write access to browser's cookies. + * + * Only a simple Object is exposed and by adding or removing properties to/from + * this object, new cookies are created/deleted at the end of current $eval. + * + * Requires the {@link ngCookies `ngCookies`} module to be installed. + * + * @example + + + + + + */ + factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) { + var cookies = {}, + lastCookies = {}, + lastBrowserCookies, + runEval = false, + copy = angular.copy, + isUndefined = angular.isUndefined; + + //creates a poller fn that copies all cookies from the $browser to service & inits the service + $browser.addPollFn(function() { + var currentCookies = $browser.cookies(); + if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl + lastBrowserCookies = currentCookies; + copy(currentCookies, lastCookies); + copy(currentCookies, cookies); + if (runEval) $rootScope.$apply(); + } + })(); + + runEval = true; + + //at the end of each eval, push cookies + //TODO: this should happen before the "delayed" watches fire, because if some cookies are not + // strings or browser refuses to store some cookies, we update the model in the push fn. + $rootScope.$watch(push); + + return cookies; + + + /** + * Pushes all the cookies from the service to the browser and verifies if all cookies were + * stored. + */ + function push() { + var name, + value, + browserCookies, + updated; + + //delete any cookies deleted in $cookies + for (name in lastCookies) { + if (isUndefined(cookies[name])) { + $browser.cookies(name, undefined); + } + } + + //update all cookies updated in $cookies + for(name in cookies) { + value = cookies[name]; + if (!angular.isString(value)) { + if (angular.isDefined(lastCookies[name])) { + cookies[name] = lastCookies[name]; + } else { + delete cookies[name]; + } + } else if (value !== lastCookies[name]) { + $browser.cookies(name, value); + updated = true; + } + } + + //verify what was actually stored + if (updated){ + updated = false; + browserCookies = $browser.cookies(); + + for (name in cookies) { + if (cookies[name] !== browserCookies[name]) { + //delete or reset all cookies that the browser dropped from $cookies + if (isUndefined(browserCookies[name])) { + delete cookies[name]; + } else { + cookies[name] = browserCookies[name]; + } + updated = true; + } + } + } + } + }]). + + + /** + * @ngdoc object + * @name ngCookies.$cookieStore + * @requires $cookies + * + * @description + * Provides a key-value (string-object) storage, that is backed by session cookies. + * Objects put or retrieved from this storage are automatically serialized or + * deserialized by angular's toJson/fromJson. + * + * Requires the {@link ngCookies `ngCookies`} module to be installed. + * + * @example + */ + factory('$cookieStore', ['$cookies', function($cookies) { + + return { + /** + * @ngdoc method + * @name ngCookies.$cookieStore#get + * @methodOf ngCookies.$cookieStore + * + * @description + * Returns the value of given cookie key + * + * @param {string} key Id to use for lookup. + * @returns {Object} Deserialized cookie value. + */ + get: function(key) { + var value = $cookies[key]; + return value ? angular.fromJson(value) : value; + }, + + /** + * @ngdoc method + * @name ngCookies.$cookieStore#put + * @methodOf ngCookies.$cookieStore + * + * @description + * Sets a value for given cookie key + * + * @param {string} key Id for the `value`. + * @param {Object} value Value to be stored. + */ + put: function(key, value) { + $cookies[key] = angular.toJson(value); + }, + + /** + * @ngdoc method + * @name ngCookies.$cookieStore#remove + * @methodOf ngCookies.$cookieStore + * + * @description + * Remove given cookie + * + * @param {string} key Id of the key-value pair to delete. + */ + remove: function(key) { + delete $cookies[key]; + } + }; + + }]); + + +})(window, window.angular); diff --git a/app/vendor/angular/angular-cookies.min.js b/app/vendor/angular/angular-cookies.min.js new file mode 100644 index 00000000..c6956ac8 --- /dev/null +++ b/app/vendor/angular/angular-cookies.min.js @@ -0,0 +1,8 @@ +/* + AngularJS v1.2.3 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(p,f,n){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(d,b){var c={},g={},h,k=!1,l=f.copy,m=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,l(a,g),l(a,c),k&&d.$apply())})();k=!0;d.$watch(function(){var a,e,d;for(a in g)m(c[a])&&b.cookies(a,n);for(a in c)(e=c[a],f.isString(e))?e!==g[a]&&(b.cookies(a,e),d=!0):f.isDefined(g[a])?c[a]=g[a]:delete c[a];if(d)for(a in e=b.cookies(),c)c[a]!==e[a]&&(m(e[a])?delete c[a]:c[a]=e[a])}); +return c}]).factory("$cookieStore",["$cookies",function(d){return{get:function(b){return(b=d[b])?f.fromJson(b):b},put:function(b,c){d[b]=f.toJson(c)},remove:function(b){delete d[b]}}}])})(window,window.angular); +//# sourceMappingURL=angular-cookies.min.js.map diff --git a/app/vendor/angular/angular-cookies.min.js.map b/app/vendor/angular/angular-cookies.min.js.map new file mode 100644 index 00000000..a7fd1e9c --- /dev/null +++ b/app/vendor/angular/angular-cookies.min.js.map @@ -0,0 +1,8 @@ +{ +"version":3, +"file":"angular-cookies.min.js", +"lineCount":7, +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAoBtCD,CAAAE,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,QAAA,CA4BW,UA5BX,CA4BuB,CAAC,YAAD,CAAe,UAAf,CAA2B,QAAS,CAACC,CAAD,CAAaC,CAAb,CAAuB,CAAA,IACxEC,EAAU,EAD8D,CAExEC,EAAc,EAF0D,CAGxEC,CAHwE,CAIxEC,EAAU,CAAA,CAJ8D,CAKxEC,EAAOV,CAAAU,KALiE,CAMxEC,EAAcX,CAAAW,YAGlBN,EAAAO,UAAA,CAAmB,QAAQ,EAAG,CAC5B,IAAIC,EAAiBR,CAAAC,QAAA,EACjBE,EAAJ,EAA0BK,CAA1B,GACEL,CAGA,CAHqBK,CAGrB,CAFAH,CAAA,CAAKG,CAAL,CAAqBN,CAArB,CAEA,CADAG,CAAA,CAAKG,CAAL,CAAqBP,CAArB,CACA,CAAIG,CAAJ,EAAaL,CAAAU,OAAA,EAJf,CAF4B,CAA9B,CAAA,EAUAL,EAAA,CAAU,CAAA,CAKVL,EAAAW,OAAA,CASAC,QAAa,EAAG,CAAA,IACVC,CADU,CAEVC,CAFU,CAIVC,CAGJ,KAAKF,CAAL,GAAaV,EAAb,CACMI,CAAA,CAAYL,CAAA,CAAQW,CAAR,CAAZ,CAAJ,EACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBhB,CAAvB,CAKJ,KAAIgB,CAAJ,GAAYX,EAAZ,CAEE,CADAY,CACK,CADGZ,CAAA,CAAQW,CAAR,CACH,CAAAjB,CAAAoB,SAAA,CAAiBF,CAAjB,CAAL,EAMWA,CANX,GAMqBX,CAAA,CAAYU,CAAZ,CANrB,GAOEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBC,CAAvB,CACA,CAAAC,CAAA,CAAU,CAAA,CARZ,EACMnB,CAAAqB,UAAA,CAAkBd,CAAA,CAAYU,CAAZ,CAAlB,CAAJ,CACEX,CAAA,CAAQW,CAAR,CADF,CACkBV,CAAA,CAAYU,CAAZ,CADlB,CAGE,OAAOX,CAAA,CAAQW,CAAR,CASb,IAAIE,CAAJ,CAIE,IAAKF,CAAL,GAFAK,EAEahB,CAFID,CAAAC,QAAA,EAEJA,CAAAA,CAAb,CACMA,CAAA,CAAQW,CAAR,CAAJ,GAAsBK,CAAA,CAAeL,CAAf,CAAtB,GAEMN,CAAA,CAAYW,CAAA,CAAeL,CAAf,CAAZ,CAAJ,CACE,OAAOX,CAAA,CAAQW,CAAR,CADT,CAGEX,CAAA,CAAQW,CAAR,CAHF,CAGkBK,CAAA,CAAeL,CAAf,CALpB,CAlCU,CAThB,CAEA;MAAOX,EA1BqE,CAA3D,CA5BvB,CAAAH,QAAA,CA4HW,cA5HX,CA4H2B,CAAC,UAAD,CAAa,QAAQ,CAACoB,CAAD,CAAW,CAErD,MAAO,KAYAC,QAAQ,CAACC,CAAD,CAAM,CAEjB,MAAO,CADHP,CACG,CADKK,CAAA,CAASE,CAAT,CACL,EAAQzB,CAAA0B,SAAA,CAAiBR,CAAjB,CAAR,CAAkCA,CAFxB,CAZd,KA4BAS,QAAQ,CAACF,CAAD,CAAMP,CAAN,CAAa,CACxBK,CAAA,CAASE,CAAT,CAAA,CAAgBzB,CAAA4B,OAAA,CAAeV,CAAf,CADQ,CA5BrB,QA0CGW,QAAQ,CAACJ,CAAD,CAAM,CACpB,OAAOF,CAAA,CAASE,CAAT,CADa,CA1CjB,CAF8C,CAAhC,CA5H3B,CApBsC,CAArC,CAAA,CAoME1B,MApMF,CAoMUA,MAAAC,QApMV;", +"sources":["angular-cookies.js"], +"names":["window","angular","undefined","module","factory","$rootScope","$browser","cookies","lastCookies","lastBrowserCookies","runEval","copy","isUndefined","addPollFn","currentCookies","$apply","$watch","push","name","value","updated","isString","isDefined","browserCookies","$cookies","get","key","fromJson","put","toJson","remove"] +} diff --git a/app/vendor/angular/angular-csp.css b/app/vendor/angular/angular-csp.css new file mode 100644 index 00000000..585878ef --- /dev/null +++ b/app/vendor/angular/angular-csp.css @@ -0,0 +1,24 @@ +/* Include this file in your html if you are using the CSP mode. */ + +@charset "UTF-8"; + +[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], +.ng-cloak, .x-ng-cloak, +.ng-hide { + display: none !important; +} + +ng\:form { + display: block; +} + +/* The styles below ensure that the CSS transition will ALWAYS + * animate and close. A nasty bug occurs with CSS transitions where + * when the active class isn't set, or if the active class doesn't + * contain any styles to transition to, then, if ngAnimate is used, + * it will appear as if the webpage is broken due to the forever hanging + * animations. The border-spacing (!ie) and zoom (ie) CSS properties are + * used below since they trigger a transition without making the browser + * animate anything and they're both highly underused CSS properties */ +.ng-animate-start { border-spacing:1px 1px; -ms-zoom:1.0001; } +.ng-animate-active { border-spacing:0px 0px; -ms-zoom:1; } diff --git a/app/vendor/angular/angular-loader.js b/app/vendor/angular/angular-loader.js new file mode 100644 index 00000000..431ff1f0 --- /dev/null +++ b/app/vendor/angular/angular-loader.js @@ -0,0 +1,410 @@ +/** + * @license AngularJS v1.2.3 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ + +(function() {'use strict'; + +/** + * @description + * + * This object provides a utility for producing rich Error messages within + * Angular. It can be called as follows: + * + * var exampleMinErr = minErr('example'); + * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); + * + * The above creates an instance of minErr in the example namespace. The + * resulting error will have a namespaced error code of example.one. The + * resulting error will replace {0} with the value of foo, and {1} with the + * value of bar. The object is not restricted in the number of arguments it can + * take. + * + * If fewer arguments are specified than necessary for interpolation, the extra + * interpolation markers will be preserved in the final string. + * + * Since data will be parsed statically during a build step, some restrictions + * are applied with respect to how minErr instances are created and called. + * Instances should have names of the form namespaceMinErr for a minErr created + * using minErr('namespace') . Error codes, namespaces and template strings + * should all be static strings, not variables or general expressions. + * + * @param {string} module The namespace to use for the new minErr instance. + * @returns {function(string, string, ...): Error} instance + */ + +function minErr(module) { + return function () { + var code = arguments[0], + prefix = '[' + (module ? module + ':' : '') + code + '] ', + template = arguments[1], + templateArgs = arguments, + stringify = function (obj) { + if (typeof obj === 'function') { + return obj.toString().replace(/ \{[\s\S]*$/, ''); + } else if (typeof obj === 'undefined') { + return 'undefined'; + } else if (typeof obj !== 'string') { + return JSON.stringify(obj); + } + return obj; + }, + message, i; + + message = prefix + template.replace(/\{\d+\}/g, function (match) { + var index = +match.slice(1, -1), arg; + + if (index + 2 < templateArgs.length) { + arg = templateArgs[index + 2]; + if (typeof arg === 'function') { + return arg.toString().replace(/ ?\{[\s\S]*$/, ''); + } else if (typeof arg === 'undefined') { + return 'undefined'; + } else if (typeof arg !== 'string') { + return toJson(arg); + } + return arg; + } + return match; + }); + + message = message + '\nhttp://errors.angularjs.org/1.2.3/' + + (module ? module + '/' : '') + code; + for (i = 2; i < arguments.length; i++) { + message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + + encodeURIComponent(stringify(arguments[i])); + } + + return new Error(message); + }; +} + +/** + * @ngdoc interface + * @name angular.Module + * @description + * + * Interface for configuring angular {@link angular.module modules}. + */ + +function setupModuleLoader(window) { + + var $injectorMinErr = minErr('$injector'); + var ngMinErr = minErr('ng'); + + function ensure(obj, name, factory) { + return obj[name] || (obj[name] = factory()); + } + + var angular = ensure(window, 'angular', Object); + + // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap + angular.$$minErr = angular.$$minErr || minErr; + + return ensure(angular, 'module', function() { + /** @type {Object.} */ + var modules = {}; + + /** + * @ngdoc function + * @name angular.module + * @description + * + * The `angular.module` is a global place for creating, registering and retrieving Angular + * modules. + * All modules (angular core or 3rd party) that should be available to an application must be + * registered using this mechanism. + * + * When passed two or more arguments, a new module is created. If passed only one argument, an + * existing module (the name passed as the first argument to `module`) is retrieved. + * + * + * # Module + * + * A module is a collection of services, directives, filters, and configuration information. + * `angular.module` is used to configure the {@link AUTO.$injector $injector}. + * + *
+     * // Create a new module
+     * var myModule = angular.module('myModule', []);
+     *
+     * // register a new service
+     * myModule.value('appName', 'MyCoolApp');
+     *
+     * // configure existing services inside initialization blocks.
+     * myModule.config(function($locationProvider) {
+     *   // Configure existing providers
+     *   $locationProvider.hashPrefix('!');
+     * });
+     * 
+ * + * Then you can create an injector and load your modules like this: + * + *
+     * var injector = angular.injector(['ng', 'MyModule'])
+     * 
+ * + * However it's more likely that you'll just use + * {@link ng.directive:ngApp ngApp} or + * {@link angular.bootstrap} to simplify this process for you. + * + * @param {!string} name The name of the module to create or retrieve. + * @param {Array.=} requires If specified then new module is being created. If + * unspecified then the the module is being retrieved for further configuration. + * @param {Function} configFn Optional configuration function for the module. Same as + * {@link angular.Module#methods_config Module#config()}. + * @returns {module} new module with the {@link angular.Module} api. + */ + return function module(name, requires, configFn) { + var assertNotHasOwnProperty = function(name, context) { + if (name === 'hasOwnProperty') { + throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); + } + }; + + assertNotHasOwnProperty(name, 'module'); + if (requires && modules.hasOwnProperty(name)) { + modules[name] = null; + } + return ensure(modules, name, function() { + if (!requires) { + throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " + + "the module name or forgot to load it. If registering a module ensure that you " + + "specify the dependencies as the second argument.", name); + } + + /** @type {!Array.>} */ + var invokeQueue = []; + + /** @type {!Array.} */ + var runBlocks = []; + + var config = invokeLater('$injector', 'invoke'); + + /** @type {angular.Module} */ + var moduleInstance = { + // Private state + _invokeQueue: invokeQueue, + _runBlocks: runBlocks, + + /** + * @ngdoc property + * @name angular.Module#requires + * @propertyOf angular.Module + * @returns {Array.} List of module names which must be loaded before this module. + * @description + * Holds the list of modules which the injector will load before the current module is + * loaded. + */ + requires: requires, + + /** + * @ngdoc property + * @name angular.Module#name + * @propertyOf angular.Module + * @returns {string} Name of the module. + * @description + */ + name: name, + + + /** + * @ngdoc method + * @name angular.Module#provider + * @methodOf angular.Module + * @param {string} name service name + * @param {Function} providerType Construction function for creating new instance of the + * service. + * @description + * See {@link AUTO.$provide#provider $provide.provider()}. + */ + provider: invokeLater('$provide', 'provider'), + + /** + * @ngdoc method + * @name angular.Module#factory + * @methodOf angular.Module + * @param {string} name service name + * @param {Function} providerFunction Function for creating new instance of the service. + * @description + * See {@link AUTO.$provide#factory $provide.factory()}. + */ + factory: invokeLater('$provide', 'factory'), + + /** + * @ngdoc method + * @name angular.Module#service + * @methodOf angular.Module + * @param {string} name service name + * @param {Function} constructor A constructor function that will be instantiated. + * @description + * See {@link AUTO.$provide#service $provide.service()}. + */ + service: invokeLater('$provide', 'service'), + + /** + * @ngdoc method + * @name angular.Module#value + * @methodOf angular.Module + * @param {string} name service name + * @param {*} object Service instance object. + * @description + * See {@link AUTO.$provide#value $provide.value()}. + */ + value: invokeLater('$provide', 'value'), + + /** + * @ngdoc method + * @name angular.Module#constant + * @methodOf angular.Module + * @param {string} name constant name + * @param {*} object Constant value. + * @description + * Because the constant are fixed, they get applied before other provide methods. + * See {@link AUTO.$provide#constant $provide.constant()}. + */ + constant: invokeLater('$provide', 'constant', 'unshift'), + + /** + * @ngdoc method + * @name angular.Module#animation + * @methodOf angular.Module + * @param {string} name animation name + * @param {Function} animationFactory Factory function for creating new instance of an + * animation. + * @description + * + * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. + * + * + * Defines an animation hook that can be later used with + * {@link ngAnimate.$animate $animate} service and directives that use this service. + * + *
+           * module.animation('.animation-name', function($inject1, $inject2) {
+           *   return {
+           *     eventName : function(element, done) {
+           *       //code to run the animation
+           *       //once complete, then run done()
+           *       return function cancellationFunction(element) {
+           *         //code to cancel the animation
+           *       }
+           *     }
+           *   }
+           * })
+           * 
+ * + * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and + * {@link ngAnimate ngAnimate module} for more information. + */ + animation: invokeLater('$animateProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#filter + * @methodOf angular.Module + * @param {string} name Filter name. + * @param {Function} filterFactory Factory function for creating new instance of filter. + * @description + * See {@link ng.$filterProvider#register $filterProvider.register()}. + */ + filter: invokeLater('$filterProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#controller + * @methodOf angular.Module + * @param {string|Object} name Controller name, or an object map of controllers where the + * keys are the names and the values are the constructors. + * @param {Function} constructor Controller constructor function. + * @description + * See {@link ng.$controllerProvider#register $controllerProvider.register()}. + */ + controller: invokeLater('$controllerProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#directive + * @methodOf angular.Module + * @param {string|Object} name Directive name, or an object map of directives where the + * keys are the names and the values are the factories. + * @param {Function} directiveFactory Factory function for creating new instance of + * directives. + * @description + * See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}. + */ + directive: invokeLater('$compileProvider', 'directive'), + + /** + * @ngdoc method + * @name angular.Module#config + * @methodOf angular.Module + * @param {Function} configFn Execute this function on module load. Useful for service + * configuration. + * @description + * Use this method to register work which needs to be performed on module loading. + */ + config: config, + + /** + * @ngdoc method + * @name angular.Module#run + * @methodOf angular.Module + * @param {Function} initializationFn Execute this function after injector creation. + * Useful for application initialization. + * @description + * Use this method to register work which should be performed when the injector is done + * loading all modules. + */ + run: function(block) { + runBlocks.push(block); + return this; + } + }; + + if (configFn) { + config(configFn); + } + + return moduleInstance; + + /** + * @param {string} provider + * @param {string} method + * @param {String=} insertMethod + * @returns {angular.Module} + */ + function invokeLater(provider, method, insertMethod) { + return function() { + invokeQueue[insertMethod || 'push']([provider, method, arguments]); + return moduleInstance; + }; + } + }); + }; + }); + +} + +setupModuleLoader(window); +})(window); + +/** + * Closure compiler type information + * + * @typedef { { + * requires: !Array., + * invokeQueue: !Array.>, + * + * service: function(string, Function):angular.Module, + * factory: function(string, Function):angular.Module, + * value: function(string, *):angular.Module, + * + * filter: function(string, Function):angular.Module, + * + * init: function(Function):angular.Module + * } } + */ +angular.Module; + diff --git a/app/vendor/angular/angular-loader.min.js b/app/vendor/angular/angular-loader.min.js new file mode 100644 index 00000000..33c58308 --- /dev/null +++ b/app/vendor/angular/angular-loader.min.js @@ -0,0 +1,9 @@ +/* + AngularJS v1.2.3 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(){'use strict';function d(a){return function(){var c=arguments[0],b,c="["+(a?a+":":"")+c+"] http://errors.angularjs.org/1.2.3/"+(a?a+"/":"")+c;for(b=1;b + * + * See {@link ngResource.$resource `$resource`} for usage. + */ + +/** + * @ngdoc object + * @name ngResource.$resource + * @requires $http + * + * @description + * A factory which creates a resource object that lets you interact with + * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources. + * + * The returned resource object has action methods which provide high-level behaviors without + * the need to interact with the low level {@link ng.$http $http} service. + * + * Requires the {@link ngResource `ngResource`} module to be installed. + * + * @param {string} url A parametrized URL template with parameters prefixed by `:` as in + * `/user/:username`. If you are using a URL with a port number (e.g. + * `http://example.com:8080/api`), it will be respected. + * + * If you are using a url with a suffix, just add the suffix, like this: + * `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')` + * or even `$resource('http://example.com/resource/:resource_id.:format')` + * If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be + * collapsed down to a single `.`. If you need this sequence to appear and not collapse then you + * can escape it with `/\.`. + * + * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in + * `actions` methods. If any of the parameter value is a function, it will be executed every time + * when a param value needs to be obtained for a request (unless the param was overridden). + * + * Each key value in the parameter object is first bound to url template if present and then any + * excess keys are appended to the url search query after the `?`. + * + * Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in + * URL `/path/greet?salutation=Hello`. + * + * If the parameter value is prefixed with `@` then the value of that parameter is extracted from + * the data object (useful for non-GET operations). + * + * @param {Object.=} actions Hash with declaration of custom action that should extend the + * default set of resource actions. The declaration should be created in the format of {@link + * ng.$http#usage_parameters $http.config}: + * + * {action1: {method:?, params:?, isArray:?, headers:?, ...}, + * action2: {method:?, params:?, isArray:?, headers:?, ...}, + * ...} + * + * Where: + * + * - **`action`** – {string} – The name of action. This name becomes the name of the method on + * your resource object. + * - **`method`** – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`, + * `DELETE`, and `JSONP`. + * - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of + * the parameter value is a function, it will be executed every time when a param value needs to + * be obtained for a request (unless the param was overridden). + * - **`url`** – {string} – action specific `url` override. The url templating is supported just + * like for the resource-level urls. + * - **`isArray`** – {boolean=} – If true then the returned object for this action is an array, + * see `returns` section. + * - **`transformRequest`** – + * `{function(data, headersGetter)|Array.}` – + * transform function or an array of such functions. The transform function takes the http + * request body and headers and returns its transformed (typically serialized) version. + * - **`transformResponse`** – + * `{function(data, headersGetter)|Array.}` – + * transform function or an array of such functions. The transform function takes the http + * response body and headers and returns its transformed (typically deserialized) version. + * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the + * GET request, otherwise if a cache instance built with + * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for + * caching. + * - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that + * should abort the request when resolved. + * - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the + * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5 + * requests with credentials} for more information. + * - **`responseType`** - `{string}` - see {@link + * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}. + * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods - + * `response` and `responseError`. Both `response` and `responseError` interceptors get called + * with `http response` object. See {@link ng.$http $http interceptors}. + * + * @returns {Object} A resource "class" object with methods for the default set of resource actions + * optionally extended with custom `actions`. The default set contains these actions: + * + * { 'get': {method:'GET'}, + * 'save': {method:'POST'}, + * 'query': {method:'GET', isArray:true}, + * 'remove': {method:'DELETE'}, + * 'delete': {method:'DELETE'} }; + * + * Calling these methods invoke an {@link ng.$http} with the specified http method, + * destination and parameters. When the data is returned from the server then the object is an + * instance of the resource class. The actions `save`, `remove` and `delete` are available on it + * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create, + * read, update, delete) on server-side data like this: + *
+        var User = $resource('/user/:userId', {userId:'@id'});
+        var user = User.get({userId:123}, function() {
+          user.abc = true;
+          user.$save();
+        });
+     
+ * + * It is important to realize that invoking a $resource object method immediately returns an + * empty reference (object or array depending on `isArray`). Once the data is returned from the + * server the existing reference is populated with the actual data. This is a useful trick since + * usually the resource is assigned to a model which is then rendered by the view. Having an empty + * object results in no rendering, once the data arrives from the server then the object is + * populated with the data and the view automatically re-renders itself showing the new data. This + * means that in most cases one never has to write a callback function for the action methods. + * + * The action methods on the class object or instance object can be invoked with the following + * parameters: + * + * - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])` + * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])` + * - non-GET instance actions: `instance.$action([parameters], [success], [error])` + * + * Success callback is called with (value, responseHeaders) arguments. Error callback is called + * with (httpResponse) argument. + * + * Class actions return empty instance (with additional properties below). + * Instance actions return promise of the action. + * + * The Resource instances and collection have these additional properties: + * + * - `$promise`: the {@link ng.$q promise} of the original server interaction that created this + * instance or collection. + * + * On success, the promise is resolved with the same resource instance or collection object, + * updated with data from server. This makes it easy to use in + * {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view + * rendering until the resource(s) are loaded. + * + * On failure, the promise is resolved with the {@link ng.$http http response} object, without + * the `resource` property. + * + * - `$resolved`: `true` after first server interaction is completed (either with success or + * rejection), `false` before that. Knowing if the Resource has been resolved is useful in + * data-binding. + * + * @example + * + * # Credit card resource + * + *
+     // Define CreditCard class
+     var CreditCard = $resource('/user/:userId/card/:cardId',
+      {userId:123, cardId:'@id'}, {
+       charge: {method:'POST', params:{charge:true}}
+      });
+
+     // We can retrieve a collection from the server
+     var cards = CreditCard.query(function() {
+       // GET: /user/123/card
+       // server returns: [ {id:456, number:'1234', name:'Smith'} ];
+
+       var card = cards[0];
+       // each item is an instance of CreditCard
+       expect(card instanceof CreditCard).toEqual(true);
+       card.name = "J. Smith";
+       // non GET methods are mapped onto the instances
+       card.$save();
+       // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
+       // server returns: {id:456, number:'1234', name: 'J. Smith'};
+
+       // our custom method is mapped as well.
+       card.$charge({amount:9.99});
+       // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
+     });
+
+     // we can create an instance as well
+     var newCard = new CreditCard({number:'0123'});
+     newCard.name = "Mike Smith";
+     newCard.$save();
+     // POST: /user/123/card {number:'0123', name:'Mike Smith'}
+     // server returns: {id:789, number:'01234', name: 'Mike Smith'};
+     expect(newCard.id).toEqual(789);
+ * 
+ * + * The object returned from this function execution is a resource "class" which has "static" method + * for each action in the definition. + * + * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and + * `headers`. + * When the data is returned from the server then the object is an instance of the resource type and + * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD + * operations (create, read, update, delete) on server-side data. + +
+     var User = $resource('/user/:userId', {userId:'@id'});
+     var user = User.get({userId:123}, function() {
+       user.abc = true;
+       user.$save();
+     });
+   
+ * + * It's worth noting that the success callback for `get`, `query` and other methods gets passed + * in the response that came from the server as well as $http header getter function, so one + * could rewrite the above example and get access to http headers as: + * +
+     var User = $resource('/user/:userId', {userId:'@id'});
+     User.get({userId:123}, function(u, getResponseHeaders){
+       u.abc = true;
+       u.$save(function(u, putResponseHeaders) {
+         //u => saved user object
+         //putResponseHeaders => $http header getter
+       });
+     });
+   
+ */ +angular.module('ngResource', ['ng']). + factory('$resource', ['$http', '$q', function($http, $q) { + + var DEFAULT_ACTIONS = { + 'get': {method:'GET'}, + 'save': {method:'POST'}, + 'query': {method:'GET', isArray:true}, + 'remove': {method:'DELETE'}, + 'delete': {method:'DELETE'} + }; + var noop = angular.noop, + forEach = angular.forEach, + extend = angular.extend, + copy = angular.copy, + isFunction = angular.isFunction; + + /** + * We need our custom method because encodeURIComponent is too aggressive and doesn't follow + * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path + * segments: + * segment = *pchar + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * pct-encoded = "%" HEXDIG HEXDIG + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ + function encodeUriSegment(val) { + return encodeUriQuery(val, true). + replace(/%26/gi, '&'). + replace(/%3D/gi, '='). + replace(/%2B/gi, '+'); + } + + + /** + * This method is intended for encoding *key* or *value* parts of query component. We need a + * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't + * have to be encoded per http://tools.ietf.org/html/rfc3986: + * query = *( pchar / "/" / "?" ) + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * pct-encoded = "%" HEXDIG HEXDIG + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ + function encodeUriQuery(val, pctEncodeSpaces) { + return encodeURIComponent(val). + replace(/%40/gi, '@'). + replace(/%3A/gi, ':'). + replace(/%24/g, '$'). + replace(/%2C/gi, ','). + replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); + } + + function Route(template, defaults) { + this.template = template; + this.defaults = defaults || {}; + this.urlParams = {}; + } + + Route.prototype = { + setUrlParams: function(config, params, actionUrl) { + var self = this, + url = actionUrl || self.template, + val, + encodedVal; + + var urlParams = self.urlParams = {}; + forEach(url.split(/\W/), function(param){ + if (param === 'hasOwnProperty') { + throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name."); + } + if (!(new RegExp("^\\d+$").test(param)) && param && + (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) { + urlParams[param] = true; + } + }); + url = url.replace(/\\:/g, ':'); + + params = params || {}; + forEach(self.urlParams, function(_, urlParam){ + val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam]; + if (angular.isDefined(val) && val !== null) { + encodedVal = encodeUriSegment(val); + url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), encodedVal + "$1"); + } else { + url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match, + leadingSlashes, tail) { + if (tail.charAt(0) == '/') { + return tail; + } else { + return leadingSlashes + tail; + } + }); + } + }); + + // strip trailing slashes and set the url + url = url.replace(/\/+$/, ''); + // then replace collapse `/.` if found in the last URL path segment before the query + // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x` + url = url.replace(/\/\.(?=\w+($|\?))/, '.'); + // replace escaped `/\.` with `/.` + config.url = url.replace(/\/\\\./, '/.'); + + + // set params - delegate param encoding to $http + forEach(params, function(value, key){ + if (!self.urlParams[key]) { + config.params = config.params || {}; + config.params[key] = value; + } + }); + } + }; + + + function resourceFactory(url, paramDefaults, actions) { + var route = new Route(url); + + actions = extend({}, DEFAULT_ACTIONS, actions); + + function extractParams(data, actionParams){ + var ids = {}; + actionParams = extend({}, paramDefaults, actionParams); + forEach(actionParams, function(value, key){ + if (isFunction(value)) { value = value(); } + ids[key] = value && value.charAt && value.charAt(0) == '@' ? + lookupDottedPath(data, value.substr(1)) : value; + }); + return ids; + } + + function defaultResponseInterceptor(response) { + return response.resource; + } + + function Resource(value){ + copy(value || {}, this); + } + + forEach(actions, function(action, name) { + var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method); + + Resource[name] = function(a1, a2, a3, a4) { + var params = {}, data, success, error; + + /* jshint -W086 */ /* (purposefully fall through case statements) */ + switch(arguments.length) { + case 4: + error = a4; + success = a3; + //fallthrough + case 3: + case 2: + if (isFunction(a2)) { + if (isFunction(a1)) { + success = a1; + error = a2; + break; + } + + success = a2; + error = a3; + //fallthrough + } else { + params = a1; + data = a2; + success = a3; + break; + } + case 1: + if (isFunction(a1)) success = a1; + else if (hasBody) data = a1; + else params = a1; + break; + case 0: break; + default: + throw $resourceMinErr('badargs', + "Expected up to 4 arguments [params, data, success, error], got {0} arguments", + arguments.length); + } + /* jshint +W086 */ /* (purposefully fall through case statements) */ + + var isInstanceCall = this instanceof Resource; + var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data)); + var httpConfig = {}; + var responseInterceptor = action.interceptor && action.interceptor.response || + defaultResponseInterceptor; + var responseErrorInterceptor = action.interceptor && action.interceptor.responseError || + undefined; + + forEach(action, function(value, key) { + if (key != 'params' && key != 'isArray' && key != 'interceptor') { + httpConfig[key] = copy(value); + } + }); + + if (hasBody) httpConfig.data = data; + route.setUrlParams(httpConfig, + extend({}, extractParams(data, action.params || {}), params), + action.url); + + var promise = $http(httpConfig).then(function(response) { + var data = response.data, + promise = value.$promise; + + if (data) { + // Need to convert action.isArray to boolean in case it is undefined + // jshint -W018 + if ( angular.isArray(data) !== (!!action.isArray) ) { + throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected ' + + 'response to contain an {0} but got an {1}', + action.isArray?'array':'object', angular.isArray(data)?'array':'object'); + } + // jshint +W018 + if (action.isArray) { + value.length = 0; + forEach(data, function(item) { + value.push(new Resource(item)); + }); + } else { + copy(data, value); + value.$promise = promise; + } + } + + value.$resolved = true; + + response.resource = value; + + return response; + }, function(response) { + value.$resolved = true; + + (error||noop)(response); + + return $q.reject(response); + }); + + promise = promise.then( + function(response) { + var value = responseInterceptor(response); + (success||noop)(value, response.headers); + return value; + }, + responseErrorInterceptor); + + if (!isInstanceCall) { + // we are creating instance / collection + // - set the initial promise + // - return the instance / collection + value.$promise = promise; + value.$resolved = false; + + return value; + } + + // instance call + return promise; + }; + + + Resource.prototype['$' + name] = function(params, success, error) { + if (isFunction(params)) { + error = success; success = params; params = {}; + } + var result = Resource[name].call(this, params, this, success, error); + return result.$promise || result; + }; + }); + + Resource.bind = function(additionalParamDefaults){ + return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions); + }; + + return Resource; + } + + return resourceFactory; + }]); + + +})(window, window.angular); diff --git a/app/vendor/angular/angular-resource.min.js b/app/vendor/angular/angular-resource.min.js new file mode 100644 index 00000000..728aee8f --- /dev/null +++ b/app/vendor/angular/angular-resource.min.js @@ -0,0 +1,12 @@ +/* + AngularJS v1.2.3 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(H,f,z){'use strict';var u=f.$$minErr("$resource"),A=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;f.module("ngResource",["ng"]).factory("$resource",["$http","$q",function(D,E){function n(f,h){this.template=f;this.defaults=h||{};this.urlParams={}}function v(m,h,k){function r(d,c){var e={};c=w({},h,c);s(c,function(a,c){t(a)&&(a=a());var g;if(a&&a.charAt&&"@"==a.charAt(0)){g=d;var b=a.substr(1);if(null==b||""===b||"hasOwnProperty"===b||!A.test("."+b))throw u("badmember",b);for(var b=b.split("."),f=0,h= +b.length;f + */ + /* global -ngRouteModule */ +var ngRouteModule = angular.module('ngRoute', ['ng']). + provider('$route', $RouteProvider); + +/** + * @ngdoc object + * @name ngRoute.$routeProvider + * @function + * + * @description + * + * Used for configuring routes. + * + * ## Example + * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`. + * + * ## Dependencies + * Requires the {@link ngRoute `ngRoute`} module to be installed. + */ +function $RouteProvider(){ + function inherit(parent, extra) { + return angular.extend(new (angular.extend(function() {}, {prototype:parent}))(), extra); + } + + var routes = {}; + + /** + * @ngdoc method + * @name ngRoute.$routeProvider#when + * @methodOf ngRoute.$routeProvider + * + * @param {string} path Route path (matched against `$location.path`). If `$location.path` + * contains redundant trailing slash or is missing one, the route will still match and the + * `$location.path` will be updated to add or drop the trailing slash to exactly match the + * route definition. + * + * * `path` can contain named groups starting with a colon (`:name`). All characters up + * to the next slash are matched and stored in `$routeParams` under the given `name` + * when the route matches. + * * `path` can contain named groups starting with a colon and ending with a star (`:name*`). + * All characters are eagerly stored in `$routeParams` under the given `name` + * when the route matches. + * * `path` can contain optional named groups with a question mark (`:name?`). + * + * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match + * `/color/brown/largecode/code/with/slashs/edit` and extract: + * + * * `color: brown` + * * `largecode: code/with/slashs`. + * + * + * @param {Object} route Mapping information to be assigned to `$route.current` on route + * match. + * + * Object properties: + * + * - `controller` – `{(string|function()=}` – Controller fn that should be associated with + * newly created scope or the name of a {@link angular.Module#controller registered + * controller} if passed as a string. + * - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be + * published to scope under the `controllerAs` name. + * - `template` – `{string=|function()=}` – html template as a string or a function that + * returns an html template as a string which should be used by {@link + * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives. + * This property takes precedence over `templateUrl`. + * + * If `template` is a function, it will be called with the following parameters: + * + * - `{Array.}` - route parameters extracted from the current + * `$location.path()` by applying the current route + * + * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html + * template that should be used by {@link ngRoute.directive:ngView ngView}. + * + * If `templateUrl` is a function, it will be called with the following parameters: + * + * - `{Array.}` - route parameters extracted from the current + * `$location.path()` by applying the current route + * + * - `resolve` - `{Object.=}` - An optional map of dependencies which should + * be injected into the controller. If any of these dependencies are promises, the router + * will wait for them all to be resolved or one to be rejected before the controller is + * instantiated. + * If all the promises are resolved successfully, the values of the resolved promises are + * injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is + * fired. If any of the promises are rejected the + * {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object + * is: + * + * - `key` – `{string}`: a name of a dependency to be injected into the controller. + * - `factory` - `{string|function}`: If `string` then it is an alias for a service. + * Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected} + * and the return value is treated as the dependency. If the result is a promise, it is + * resolved before its value is injected into the controller. Be aware that + * `ngRoute.$routeParams` will still refer to the previous route within these resolve + * functions. Use `$route.current.params` to access the new route parameters, instead. + * + * - `redirectTo` – {(string|function())=} – value to update + * {@link ng.$location $location} path with and trigger route redirection. + * + * If `redirectTo` is a function, it will be called with the following parameters: + * + * - `{Object.}` - route parameters extracted from the current + * `$location.path()` by applying the current route templateUrl. + * - `{string}` - current `$location.path()` + * - `{Object}` - current `$location.search()` + * + * The custom `redirectTo` function is expected to return a string which will be used + * to update `$location.path()` and `$location.search()`. + * + * - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()` + * or `$location.hash()` changes. + * + * If the option is set to `false` and url in the browser changes, then + * `$routeUpdate` event is broadcasted on the root scope. + * + * - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive + * + * If the option is set to `true`, then the particular route can be matched without being + * case sensitive + * + * @returns {Object} self + * + * @description + * Adds a new route definition to the `$route` service. + */ + this.when = function(path, route) { + routes[path] = angular.extend( + {reloadOnSearch: true}, + route, + path && pathRegExp(path, route) + ); + + // create redirection for trailing slashes + if (path) { + var redirectPath = (path[path.length-1] == '/') + ? path.substr(0, path.length-1) + : path +'/'; + + routes[redirectPath] = angular.extend( + {redirectTo: path}, + pathRegExp(redirectPath, route) + ); + } + + return this; + }; + + /** + * @param path {string} path + * @param opts {Object} options + * @return {?Object} + * + * @description + * Normalizes the given path, returning a regular expression + * and the original path. + * + * Inspired by pathRexp in visionmedia/express/lib/utils.js. + */ + function pathRegExp(path, opts) { + var insensitive = opts.caseInsensitiveMatch, + ret = { + originalPath: path, + regexp: path + }, + keys = ret.keys = []; + + path = path + .replace(/([().])/g, '\\$1') + .replace(/(\/)?:(\w+)([\?|\*])?/g, function(_, slash, key, option){ + var optional = option === '?' ? option : null; + var star = option === '*' ? option : null; + keys.push({ name: key, optional: !!optional }); + slash = slash || ''; + return '' + + (optional ? '' : slash) + + '(?:' + + (optional ? slash : '') + + (star && '(.+?)' || '([^/]+)') + + (optional || '') + + ')' + + (optional || ''); + }) + .replace(/([\/$\*])/g, '\\$1'); + + ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : ''); + return ret; + } + + /** + * @ngdoc method + * @name ngRoute.$routeProvider#otherwise + * @methodOf ngRoute.$routeProvider + * + * @description + * Sets route definition that will be used on route change when no other route definition + * is matched. + * + * @param {Object} params Mapping information to be assigned to `$route.current`. + * @returns {Object} self + */ + this.otherwise = function(params) { + this.when(null, params); + return this; + }; + + + this.$get = ['$rootScope', + '$location', + '$routeParams', + '$q', + '$injector', + '$http', + '$templateCache', + '$sce', + function($rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) { + + /** + * @ngdoc object + * @name ngRoute.$route + * @requires $location + * @requires $routeParams + * + * @property {Object} current Reference to the current route definition. + * The route definition contains: + * + * - `controller`: The controller constructor as define in route definition. + * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for + * controller instantiation. The `locals` contain + * the resolved values of the `resolve` map. Additionally the `locals` also contain: + * + * - `$scope` - The current route scope. + * - `$template` - The current route template HTML. + * + * @property {Array.} routes Array of all configured routes. + * + * @description + * `$route` is used for deep-linking URLs to controllers and views (HTML partials). + * It watches `$location.url()` and tries to map the path to an existing route definition. + * + * Requires the {@link ngRoute `ngRoute`} module to be installed. + * + * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API. + * + * The `$route` service is typically used in conjunction with the + * {@link ngRoute.directive:ngView `ngView`} directive and the + * {@link ngRoute.$routeParams `$routeParams`} service. + * + * @example + This example shows how changing the URL hash causes the `$route` to match a route against the + URL, and the `ngView` pulls in the partial. + + Note that this example is using {@link ng.directive:script inlined templates} + to get it working on jsfiddle as well. + + + +
+ Choose: + Moby | + Moby: Ch1 | + Gatsby | + Gatsby: Ch4 | + Scarlet Letter
+ +
+
+ +
$location.path() = {{$location.path()}}
+
$route.current.templateUrl = {{$route.current.templateUrl}}
+
$route.current.params = {{$route.current.params}}
+
$route.current.scope.name = {{$route.current.scope.name}}
+
$routeParams = {{$routeParams}}
+
+
+ + + controller: {{name}}
+ Book Id: {{params.bookId}}
+
+ + + controller: {{name}}
+ Book Id: {{params.bookId}}
+ Chapter Id: {{params.chapterId}} +
+ + + angular.module('ngViewExample', ['ngRoute']) + + .config(function($routeProvider, $locationProvider) { + $routeProvider.when('/Book/:bookId', { + templateUrl: 'book.html', + controller: BookCntl, + resolve: { + // I will cause a 1 second delay + delay: function($q, $timeout) { + var delay = $q.defer(); + $timeout(delay.resolve, 1000); + return delay.promise; + } + } + }); + $routeProvider.when('/Book/:bookId/ch/:chapterId', { + templateUrl: 'chapter.html', + controller: ChapterCntl + }); + + // configure html5 to get links working on jsfiddle + $locationProvider.html5Mode(true); + }); + + function MainCntl($scope, $route, $routeParams, $location) { + $scope.$route = $route; + $scope.$location = $location; + $scope.$routeParams = $routeParams; + } + + function BookCntl($scope, $routeParams) { + $scope.name = "BookCntl"; + $scope.params = $routeParams; + } + + function ChapterCntl($scope, $routeParams) { + $scope.name = "ChapterCntl"; + $scope.params = $routeParams; + } + + + + it('should load and compile correct template', function() { + element('a:contains("Moby: Ch1")').click(); + var content = element('.doc-example-live [ng-view]').text(); + expect(content).toMatch(/controller\: ChapterCntl/); + expect(content).toMatch(/Book Id\: Moby/); + expect(content).toMatch(/Chapter Id\: 1/); + + element('a:contains("Scarlet")').click(); + sleep(2); // promises are not part of scenario waiting + content = element('.doc-example-live [ng-view]').text(); + expect(content).toMatch(/controller\: BookCntl/); + expect(content).toMatch(/Book Id\: Scarlet/); + }); + +
+ */ + + /** + * @ngdoc event + * @name ngRoute.$route#$routeChangeStart + * @eventOf ngRoute.$route + * @eventType broadcast on root scope + * @description + * Broadcasted before a route change. At this point the route services starts + * resolving all of the dependencies needed for the route change to occurs. + * Typically this involves fetching the view template as well as any dependencies + * defined in `resolve` route property. Once all of the dependencies are resolved + * `$routeChangeSuccess` is fired. + * + * @param {Object} angularEvent Synthetic event object. + * @param {Route} next Future route information. + * @param {Route} current Current route information. + */ + + /** + * @ngdoc event + * @name ngRoute.$route#$routeChangeSuccess + * @eventOf ngRoute.$route + * @eventType broadcast on root scope + * @description + * Broadcasted after a route dependencies are resolved. + * {@link ngRoute.directive:ngView ngView} listens for the directive + * to instantiate the controller and render the view. + * + * @param {Object} angularEvent Synthetic event object. + * @param {Route} current Current route information. + * @param {Route|Undefined} previous Previous route information, or undefined if current is + * first route entered. + */ + + /** + * @ngdoc event + * @name ngRoute.$route#$routeChangeError + * @eventOf ngRoute.$route + * @eventType broadcast on root scope + * @description + * Broadcasted if any of the resolve promises are rejected. + * + * @param {Object} angularEvent Synthetic event object + * @param {Route} current Current route information. + * @param {Route} previous Previous route information. + * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise. + */ + + /** + * @ngdoc event + * @name ngRoute.$route#$routeUpdate + * @eventOf ngRoute.$route + * @eventType broadcast on root scope + * @description + * + * The `reloadOnSearch` property has been set to false, and we are reusing the same + * instance of the Controller. + */ + + var forceReload = false, + $route = { + routes: routes, + + /** + * @ngdoc method + * @name ngRoute.$route#reload + * @methodOf ngRoute.$route + * + * @description + * Causes `$route` service to reload the current route even if + * {@link ng.$location $location} hasn't changed. + * + * As a result of that, {@link ngRoute.directive:ngView ngView} + * creates new scope, reinstantiates the controller. + */ + reload: function() { + forceReload = true; + $rootScope.$evalAsync(updateRoute); + } + }; + + $rootScope.$on('$locationChangeSuccess', updateRoute); + + return $route; + + ///////////////////////////////////////////////////// + + /** + * @param on {string} current url + * @param route {Object} route regexp to match the url against + * @return {?Object} + * + * @description + * Check if the route matches the current url. + * + * Inspired by match in + * visionmedia/express/lib/router/router.js. + */ + function switchRouteMatcher(on, route) { + var keys = route.keys, + params = {}; + + if (!route.regexp) return null; + + var m = route.regexp.exec(on); + if (!m) return null; + + for (var i = 1, len = m.length; i < len; ++i) { + var key = keys[i - 1]; + + var val = 'string' == typeof m[i] + ? decodeURIComponent(m[i]) + : m[i]; + + if (key && val) { + params[key.name] = val; + } + } + return params; + } + + function updateRoute() { + var next = parseRoute(), + last = $route.current; + + if (next && last && next.$$route === last.$$route + && angular.equals(next.pathParams, last.pathParams) + && !next.reloadOnSearch && !forceReload) { + last.params = next.params; + angular.copy(last.params, $routeParams); + $rootScope.$broadcast('$routeUpdate', last); + } else if (next || last) { + forceReload = false; + $rootScope.$broadcast('$routeChangeStart', next, last); + $route.current = next; + if (next) { + if (next.redirectTo) { + if (angular.isString(next.redirectTo)) { + $location.path(interpolate(next.redirectTo, next.params)).search(next.params) + .replace(); + } else { + $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search())) + .replace(); + } + } + } + + $q.when(next). + then(function() { + if (next) { + var locals = angular.extend({}, next.resolve), + template, templateUrl; + + angular.forEach(locals, function(value, key) { + locals[key] = angular.isString(value) ? + $injector.get(value) : $injector.invoke(value); + }); + + if (angular.isDefined(template = next.template)) { + if (angular.isFunction(template)) { + template = template(next.params); + } + } else if (angular.isDefined(templateUrl = next.templateUrl)) { + if (angular.isFunction(templateUrl)) { + templateUrl = templateUrl(next.params); + } + templateUrl = $sce.getTrustedResourceUrl(templateUrl); + if (angular.isDefined(templateUrl)) { + next.loadedTemplateUrl = templateUrl; + template = $http.get(templateUrl, {cache: $templateCache}). + then(function(response) { return response.data; }); + } + } + if (angular.isDefined(template)) { + locals['$template'] = template; + } + return $q.all(locals); + } + }). + // after route change + then(function(locals) { + if (next == $route.current) { + if (next) { + next.locals = locals; + angular.copy(next.params, $routeParams); + } + $rootScope.$broadcast('$routeChangeSuccess', next, last); + } + }, function(error) { + if (next == $route.current) { + $rootScope.$broadcast('$routeChangeError', next, last, error); + } + }); + } + } + + + /** + * @returns the current active route, by matching it against the URL + */ + function parseRoute() { + // Match a route + var params, match; + angular.forEach(routes, function(route, path) { + if (!match && (params = switchRouteMatcher($location.path(), route))) { + match = inherit(route, { + params: angular.extend({}, $location.search(), params), + pathParams: params}); + match.$$route = route; + } + }); + // No route matched; fallback to "otherwise" route + return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); + } + + /** + * @returns interpolation of the redirect path with the parameters + */ + function interpolate(string, params) { + var result = []; + angular.forEach((string||'').split(':'), function(segment, i) { + if (i === 0) { + result.push(segment); + } else { + var segmentMatch = segment.match(/(\w+)(.*)/); + var key = segmentMatch[1]; + result.push(params[key]); + result.push(segmentMatch[2] || ''); + delete params[key]; + } + }); + return result.join(''); + } + }]; +} + +ngRouteModule.provider('$routeParams', $RouteParamsProvider); + + +/** + * @ngdoc object + * @name ngRoute.$routeParams + * @requires $route + * + * @description + * The `$routeParams` service allows you to retrieve the current set of route parameters. + * + * Requires the {@link ngRoute `ngRoute`} module to be installed. + * + * The route parameters are a combination of {@link ng.$location `$location`}'s + * {@link ng.$location#methods_search `search()`} and {@link ng.$location#methods_path `path()`}. + * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched. + * + * In case of parameter name collision, `path` params take precedence over `search` params. + * + * The service guarantees that the identity of the `$routeParams` object will remain unchanged + * (but its properties will likely change) even when a route change occurs. + * + * Note that the `$routeParams` are only updated *after* a route change completes successfully. + * This means that you cannot rely on `$routeParams` being correct in route resolve functions. + * Instead you can use `$route.current.params` to access the new route's parameters. + * + * @example + *
+ *  // Given:
+ *  // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
+ *  // Route: /Chapter/:chapterId/Section/:sectionId
+ *  //
+ *  // Then
+ *  $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
+ * 
+ */ +function $RouteParamsProvider() { + this.$get = function() { return {}; }; +} + +ngRouteModule.directive('ngView', ngViewFactory); + +/** + * @ngdoc directive + * @name ngRoute.directive:ngView + * @restrict ECA + * + * @description + * # Overview + * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by + * including the rendered template of the current route into the main layout (`index.html`) file. + * Every time the current route changes, the included view changes with it according to the + * configuration of the `$route` service. + * + * Requires the {@link ngRoute `ngRoute`} module to be installed. + * + * @animations + * enter - animation is used to bring new content into the browser. + * leave - animation is used to animate existing content away. + * + * The enter and leave animation occur concurrently. + * + * @scope + * @priority 400 + * @example + + +
+ Choose: + Moby | + Moby: Ch1 | + Gatsby | + Gatsby: Ch4 | + Scarlet Letter
+ +
+
+
+
+ +
$location.path() = {{main.$location.path()}}
+
$route.current.templateUrl = {{main.$route.current.templateUrl}}
+
$route.current.params = {{main.$route.current.params}}
+
$route.current.scope.name = {{main.$route.current.scope.name}}
+
$routeParams = {{main.$routeParams}}
+
+
+ + +
+ controller: {{book.name}}
+ Book Id: {{book.params.bookId}}
+
+
+ + +
+ controller: {{chapter.name}}
+ Book Id: {{chapter.params.bookId}}
+ Chapter Id: {{chapter.params.chapterId}} +
+
+ + + .view-animate-container { + position:relative; + height:100px!important; + position:relative; + background:white; + border:1px solid black; + height:40px; + overflow:hidden; + } + + .view-animate { + padding:10px; + } + + .view-animate.ng-enter, .view-animate.ng-leave { + -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s; + transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s; + + display:block; + width:100%; + border-left:1px solid black; + + position:absolute; + top:0; + left:0; + right:0; + bottom:0; + padding:10px; + } + + .view-animate.ng-enter { + left:100%; + } + .view-animate.ng-enter.ng-enter-active { + left:0; + } + .view-animate.ng-leave.ng-leave-active { + left:-100%; + } + + + + angular.module('ngViewExample', ['ngRoute', 'ngAnimate'], + function($routeProvider, $locationProvider) { + $routeProvider.when('/Book/:bookId', { + templateUrl: 'book.html', + controller: BookCntl, + controllerAs: 'book' + }); + $routeProvider.when('/Book/:bookId/ch/:chapterId', { + templateUrl: 'chapter.html', + controller: ChapterCntl, + controllerAs: 'chapter' + }); + + // configure html5 to get links working on jsfiddle + $locationProvider.html5Mode(true); + }); + + function MainCntl($route, $routeParams, $location) { + this.$route = $route; + this.$location = $location; + this.$routeParams = $routeParams; + } + + function BookCntl($routeParams) { + this.name = "BookCntl"; + this.params = $routeParams; + } + + function ChapterCntl($routeParams) { + this.name = "ChapterCntl"; + this.params = $routeParams; + } + + + + it('should load and compile correct template', function() { + element('a:contains("Moby: Ch1")').click(); + var content = element('.doc-example-live [ng-view]').text(); + expect(content).toMatch(/controller\: ChapterCntl/); + expect(content).toMatch(/Book Id\: Moby/); + expect(content).toMatch(/Chapter Id\: 1/); + + element('a:contains("Scarlet")').click(); + content = element('.doc-example-live [ng-view]').text(); + expect(content).toMatch(/controller\: BookCntl/); + expect(content).toMatch(/Book Id\: Scarlet/); + }); + +
+ */ + + +/** + * @ngdoc event + * @name ngRoute.directive:ngView#$viewContentLoaded + * @eventOf ngRoute.directive:ngView + * @eventType emit on the current ngView scope + * @description + * Emitted every time the ngView content is reloaded. + */ +ngViewFactory.$inject = ['$route', '$anchorScroll', '$compile', '$controller', '$animate']; +function ngViewFactory( $route, $anchorScroll, $compile, $controller, $animate) { + return { + restrict: 'ECA', + terminal: true, + priority: 400, + transclude: 'element', + link: function(scope, $element, attr, ctrl, $transclude) { + var currentScope, + currentElement, + autoScrollExp = attr.autoscroll, + onloadExp = attr.onload || ''; + + scope.$on('$routeChangeSuccess', update); + update(); + + function cleanupLastView() { + if (currentScope) { + currentScope.$destroy(); + currentScope = null; + } + if(currentElement) { + $animate.leave(currentElement); + currentElement = null; + } + } + + function update() { + var locals = $route.current && $route.current.locals, + template = locals && locals.$template; + + if (template) { + var newScope = scope.$new(); + + // Note: This will also link all children of ng-view that were contained in the original + // html. If that content contains controllers, ... they could pollute/change the scope. + // However, using ng-view on an element with additional content does not make sense... + // Note: We can't remove them in the cloneAttchFn of $transclude as that + // function is called before linking the content, which would apply child + // directives to non existing elements. + var clone = $transclude(newScope, angular.noop); + clone.html(template); + $animate.enter(clone, null, currentElement || $element, function onNgViewEnter () { + if (angular.isDefined(autoScrollExp) + && (!autoScrollExp || scope.$eval(autoScrollExp))) { + $anchorScroll(); + } + }); + + cleanupLastView(); + + var link = $compile(clone.contents()), + current = $route.current; + + currentScope = current.scope = newScope; + currentElement = clone; + + if (current.controller) { + locals.$scope = currentScope; + var controller = $controller(current.controller, locals); + if (current.controllerAs) { + currentScope[current.controllerAs] = controller; + } + clone.data('$ngControllerController', controller); + clone.children().data('$ngControllerController', controller); + } + + link(currentScope); + currentScope.$emit('$viewContentLoaded'); + currentScope.$eval(onloadExp); + } else { + cleanupLastView(); + } + } + } + }; +} + + +})(window, window.angular); diff --git a/app/vendor/angular/angular-route.min.js b/app/vendor/angular/angular-route.min.js new file mode 100644 index 00000000..5870a6a8 --- /dev/null +++ b/app/vendor/angular/angular-route.min.js @@ -0,0 +1,14 @@ +/* + AngularJS v1.2.3 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(t,c,A){'use strict';function x(r,m,d,b,h){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(l,z,k,B,w){function v(){g&&(g.$destroy(),g=null);q&&(h.leave(q),q=null)}function u(){var a=r.current&&r.current.locals,e=a&&a.$template;if(e){var y=l.$new(),s=w(y,c.noop);s.html(e);h.enter(s,null,q||z,function(){!c.isDefined(n)||n&&!l.$eval(n)||m()});v();var e=d(s.contents()),f=r.current;g=f.scope=y;q=s;f.controller&&(a.$scope=g,a=b(f.controller,a),f.controllerAs&& +(g[f.controllerAs]=a),s.data("$ngControllerController",a),s.children().data("$ngControllerController",a));e(g);g.$emit("$viewContentLoaded");g.$eval(p)}else v()}var g,q,n=k.autoscroll,p=k.onload||"";l.$on("$routeChangeSuccess",u);u()}}}t=c.module("ngRoute",["ng"]).provider("$route",function(){function r(b,h){return c.extend(new (c.extend(function(){},{prototype:b})),h)}function m(b,c){var l=c.caseInsensitiveMatch,d={originalPath:b,regexp:b},k=d.keys=[];b=b.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?|\*])?/g, +function(b,c,h,d){b="?"===d?d:null;d="*"===d?d:null;k.push({name:h,optional:!!b});c=c||"";return""+(b?"":c)+"(?:"+(b?c:"")+(d&&"(.+?)"||"([^/]+)")+(b||"")+")"+(b||"")}).replace(/([\/$\*])/g,"\\$1");d.regexp=RegExp("^"+b+"$",l?"i":"");return d}var d={};this.when=function(b,h){d[b]=c.extend({reloadOnSearch:!0},h,b&&m(b,h));if(b){var l="/"==b[b.length-1]?b.substr(0,b.length-1):b+"/";d[l]=c.extend({redirectTo:b},m(l,h))}return this};this.otherwise=function(b){this.when(null,b);return this};this.$get= +["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(b,h,l,m,k,t,w,v){function u(){var a=g(),e=p.current;if(a&&e&&a.$$route===e.$$route&&c.equals(a.pathParams,e.pathParams)&&!a.reloadOnSearch&&!n)e.params=a.params,c.copy(e.params,l),b.$broadcast("$routeUpdate",e);else if(a||e)n=!1,b.$broadcast("$routeChangeStart",a,e),(p.current=a)&&a.redirectTo&&(c.isString(a.redirectTo)?h.path(q(a.redirectTo,a.params)).search(a.params).replace():h.url(a.redirectTo(a.pathParams, +h.path(),h.search())).replace()),m.when(a).then(function(){if(a){var b=c.extend({},a.resolve),e,f;c.forEach(b,function(a,e){b[e]=c.isString(a)?k.get(a):k.invoke(a)});c.isDefined(e=a.template)?c.isFunction(e)&&(e=e(a.params)):c.isDefined(f=a.templateUrl)&&(c.isFunction(f)&&(f=f(a.params)),f=v.getTrustedResourceUrl(f),c.isDefined(f)&&(a.loadedTemplateUrl=f,e=t.get(f,{cache:w}).then(function(a){return a.data})));c.isDefined(e)&&(b.$template=e);return m.all(b)}}).then(function(d){a==p.current&&(a&&(a.locals= +d,c.copy(a.params,l)),b.$broadcast("$routeChangeSuccess",a,e))},function(c){a==p.current&&b.$broadcast("$routeChangeError",a,e,c)})}function g(){var a,b;c.forEach(d,function(d,l){var f;if(f=!b){var g=h.path();f=d.keys;var m={};if(d.regexp)if(g=d.regexp.exec(g)){for(var k=1,q=g.length;k + * + * See {@link ngSanitize.$sanitize `$sanitize`} for usage. + */ + +/* + * HTML Parser By Misko Hevery (misko@hevery.com) + * based on: HTML Parser By John Resig (ejohn.org) + * Original code by Erik Arvidsson, Mozilla Public License + * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js + * + * // Use like so: + * htmlParser(htmlString, { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + */ + + +/** + * @ngdoc service + * @name ngSanitize.$sanitize + * @function + * + * @description + * The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are + * then serialized back to properly escaped html string. This means that no unsafe input can make + * it into the returned string, however, since our parser is more strict than a typical browser + * parser, it's possible that some obscure input, which would be recognized as valid HTML by a + * browser, won't make it through the sanitizer. + * The whitelist is configured using the functions `aHrefSanitizationWhitelist` and + * `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}. + * + * @param {string} html Html input. + * @returns {string} Sanitized html. + * + * @example + + + +
+ Snippet: + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveHowSourceRendered
ng-bind-htmlAutomatically uses $sanitize
<div ng-bind-html="snippet">
</div>
ng-bind-htmlBypass $sanitize by explicitly trusting the dangerous value +
<div ng-bind-html="deliberatelyTrustDangerousSnippet()">
+</div>
+
ng-bindAutomatically escapes
<div ng-bind="snippet">
</div>
+
+
+ + it('should sanitize the html snippet by default', function() { + expect(using('#bind-html-with-sanitize').element('div').html()). + toBe('

an html\nclick here\nsnippet

'); + }); + + it('should inline raw snippet if bound to a trusted value', function() { + expect(using('#bind-html-with-trust').element("div").html()). + toBe("

an html\n" + + "click here\n" + + "snippet

"); + }); + + it('should escape snippet without any filter', function() { + expect(using('#bind-default').element('div').html()). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + + it('should update', function() { + input('snippet').enter('new text'); + expect(using('#bind-html-with-sanitize').element('div').html()).toBe('new text'); + expect(using('#bind-html-with-trust').element('div').html()).toBe( + 'new text'); + expect(using('#bind-default').element('div').html()).toBe( + "new <b onclick=\"alert(1)\">text</b>"); + }); +
+
+ */ +function $SanitizeProvider() { + this.$get = ['$$sanitizeUri', function($$sanitizeUri) { + return function(html) { + var buf = []; + htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { + return !/^unsafe/.test($$sanitizeUri(uri, isImage)); + })); + return buf.join(''); + }; + }]; +} + +function sanitizeText(chars) { + var buf = []; + var writer = htmlSanitizeWriter(buf, angular.noop); + writer.chars(chars); + return buf.join(''); +} + + +// Regular Expressions for parsing tags and attributes +var START_TAG_REGEXP = + /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/, + END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/, + ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, + BEGIN_TAG_REGEXP = /^/g, + DOCTYPE_REGEXP = /]*?)>/i, + CDATA_REGEXP = //g, + // Match everything outside of normal chars and " (quote character) + NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; + + +// Good source of info about elements and attributes +// http://dev.w3.org/html5/spec/Overview.html#semantics +// http://simon.html5.org/html-elements + +// Safe Void Elements - HTML5 +// http://dev.w3.org/html5/spec/Overview.html#void-elements +var voidElements = makeMap("area,br,col,hr,img,wbr"); + +// Elements that you can, intentionally, leave open (and which close themselves) +// http://dev.w3.org/html5/spec/Overview.html#optional-tags +var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"), + optionalEndTagInlineElements = makeMap("rp,rt"), + optionalEndTagElements = angular.extend({}, + optionalEndTagInlineElements, + optionalEndTagBlockElements); + +// Safe Block Elements - HTML5 +var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," + + "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," + + "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")); + +// Inline Elements - HTML5 +var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," + + "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," + + "samp,small,span,strike,strong,sub,sup,time,tt,u,var")); + + +// Special Elements (can contain anything) +var specialElements = makeMap("script,style"); + +var validElements = angular.extend({}, + voidElements, + blockElements, + inlineElements, + optionalEndTagElements); + +//Attributes that have href and hence need to be sanitized +var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap"); +var validAttrs = angular.extend({}, uriAttrs, makeMap( + 'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+ + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+ + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+ + 'scope,scrolling,shape,span,start,summary,target,title,type,'+ + 'valign,value,vspace,width')); + +function makeMap(str) { + var obj = {}, items = str.split(','), i; + for (i = 0; i < items.length; i++) obj[items[i]] = true; + return obj; +} + + +/** + * @example + * htmlParser(htmlString, { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + * @param {string} html string + * @param {object} handler + */ +function htmlParser( html, handler ) { + var index, chars, match, stack = [], last = html; + stack.last = function() { return stack[ stack.length - 1 ]; }; + + while ( html ) { + chars = true; + + // Make sure we're not in a script or style element + if ( !stack.last() || !specialElements[ stack.last() ] ) { + + // Comment + if ( html.indexOf("", index) === index) { + if (handler.comment) handler.comment( html.substring( 4, index ) ); + html = html.substring( index + 3 ); + chars = false; + } + // DOCTYPE + } else if ( DOCTYPE_REGEXP.test(html) ) { + match = html.match( DOCTYPE_REGEXP ); + + if ( match ) { + html = html.replace( match[0] , ''); + chars = false; + } + // end tag + } else if ( BEGING_END_TAGE_REGEXP.test(html) ) { + match = html.match( END_TAG_REGEXP ); + + if ( match ) { + html = html.substring( match[0].length ); + match[0].replace( END_TAG_REGEXP, parseEndTag ); + chars = false; + } + + // start tag + } else if ( BEGIN_TAG_REGEXP.test(html) ) { + match = html.match( START_TAG_REGEXP ); + + if ( match ) { + html = html.substring( match[0].length ); + match[0].replace( START_TAG_REGEXP, parseStartTag ); + chars = false; + } + } + + if ( chars ) { + index = html.indexOf("<"); + + var text = index < 0 ? html : html.substring( 0, index ); + html = index < 0 ? "" : html.substring( index ); + + if (handler.chars) handler.chars( decodeEntities(text) ); + } + + } else { + html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), + function(all, text){ + text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1"); + + if (handler.chars) handler.chars( decodeEntities(text) ); + + return ""; + }); + + parseEndTag( "", stack.last() ); + } + + if ( html == last ) { + throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " + + "of html: {0}", html); + } + last = html; + } + + // Clean up any remaining tags + parseEndTag(); + + function parseStartTag( tag, tagName, rest, unary ) { + tagName = angular.lowercase(tagName); + if ( blockElements[ tagName ] ) { + while ( stack.last() && inlineElements[ stack.last() ] ) { + parseEndTag( "", stack.last() ); + } + } + + if ( optionalEndTagElements[ tagName ] && stack.last() == tagName ) { + parseEndTag( "", tagName ); + } + + unary = voidElements[ tagName ] || !!unary; + + if ( !unary ) + stack.push( tagName ); + + var attrs = {}; + + rest.replace(ATTR_REGEXP, + function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) { + var value = doubleQuotedValue + || singleQuotedValue + || unquotedValue + || ''; + + attrs[name] = decodeEntities(value); + }); + if (handler.start) handler.start( tagName, attrs, unary ); + } + + function parseEndTag( tag, tagName ) { + var pos = 0, i; + tagName = angular.lowercase(tagName); + if ( tagName ) + // Find the closest opened tag of the same type + for ( pos = stack.length - 1; pos >= 0; pos-- ) + if ( stack[ pos ] == tagName ) + break; + + if ( pos >= 0 ) { + // Close all the open elements, up the stack + for ( i = stack.length - 1; i >= pos; i-- ) + if (handler.end) handler.end( stack[ i ] ); + + // Remove the open elements from the stack + stack.length = pos; + } + } +} + +/** + * decodes all entities into regular string + * @param value + * @returns {string} A string with decoded entities. + */ +var hiddenPre=document.createElement("pre"); +function decodeEntities(value) { + if (!value) { + return ''; + } + // Note: IE8 does not preserve spaces at the start/end of innerHTML + var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/; + var parts = spaceRe.exec(value); + parts[0] = ''; + if (parts[2]) { + hiddenPre.innerHTML=parts[2].replace(//g, '>'); +} + +/** + * create an HTML/XML writer which writes to buffer + * @param {Array} buf use buf.jain('') to get out sanitized html string + * @returns {object} in the form of { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * } + */ +function htmlSanitizeWriter(buf, uriValidator){ + var ignore = false; + var out = angular.bind(buf, buf.push); + return { + start: function(tag, attrs, unary){ + tag = angular.lowercase(tag); + if (!ignore && specialElements[tag]) { + ignore = tag; + } + if (!ignore && validElements[tag] === true) { + out('<'); + out(tag); + angular.forEach(attrs, function(value, key){ + var lkey=angular.lowercase(key); + var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); + if (validAttrs[lkey] === true && + (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { + out(' '); + out(key); + out('="'); + out(encodeEntities(value)); + out('"'); + } + }); + out(unary ? '/>' : '>'); + } + }, + end: function(tag){ + tag = angular.lowercase(tag); + if (!ignore && validElements[tag] === true) { + out(''); + } + if (tag == ignore) { + ignore = false; + } + }, + chars: function(chars){ + if (!ignore) { + out(encodeEntities(chars)); + } + } + }; +} + + +// define ngSanitize module and register $sanitize service +angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider); + +/* global sanitizeText: false */ + +/** + * @ngdoc filter + * @name ngSanitize.filter:linky + * @function + * + * @description + * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and + * plain email address links. + * + * Requires the {@link ngSanitize `ngSanitize`} module to be installed. + * + * @param {string} text Input text. + * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in. + * @returns {string} Html-linkified text. + * + * @usage + + * + * @example + + + +
+ Snippet: + + + + + + + + + + + + + + + + + + + + + +
FilterSourceRendered
linky filter +
<div ng-bind-html="snippet | linky">
</div>
+
+
+
linky target +
<div ng-bind-html="snippetWithTarget | linky:'_blank'">
</div>
+
+
+
no filter
<div ng-bind="snippet">
</div>
+ + + it('should linkify the snippet with urls', function() { + expect(using('#linky-filter').binding('snippet | linky')). + toBe('Pretty text with some links: ' + + 'http://angularjs.org/, ' + + 'us@somewhere.org, ' + + 'another@somewhere.org, ' + + 'and one more: ftp://127.0.0.1/.'); + }); + + it ('should not linkify snippet without the linky filter', function() { + expect(using('#escaped-html').binding('snippet')). + toBe("Pretty text with some links:\n" + + "http://angularjs.org/,\n" + + "mailto:us@somewhere.org,\n" + + "another@somewhere.org,\n" + + "and one more: ftp://127.0.0.1/."); + }); + + it('should update', function() { + input('snippet').enter('new http://link.'); + expect(using('#linky-filter').binding('snippet | linky')). + toBe('new http://link.'); + expect(using('#escaped-html').binding('snippet')).toBe('new http://link.'); + }); + + it('should work with the target property', function() { + expect(using('#linky-target').binding("snippetWithTarget | linky:'_blank'")). + toBe('http://angularjs.org/'); + }); + + + */ +angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { + var LINKY_URL_REGEXP = + /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/, + MAILTO_REGEXP = /^mailto:/; + + return function(text, target) { + if (!text) return text; + var match; + var raw = text; + var html = []; + var url; + var i; + while ((match = raw.match(LINKY_URL_REGEXP))) { + // We can not end in these as they are sometimes found at the end of the sentence + url = match[0]; + // if we did not match ftp/http/mailto then assume mailto + if (match[2] == match[3]) url = 'mailto:' + url; + i = match.index; + addText(raw.substr(0, i)); + addLink(url, match[0].replace(MAILTO_REGEXP, '')); + raw = raw.substring(i + match[0].length); + } + addText(raw); + return $sanitize(html.join('')); + + function addText(text) { + if (!text) { + return; + } + html.push(sanitizeText(text)); + } + + function addLink(url, text) { + html.push(''); + addText(text); + html.push(''); + } + }; +}]); + + +})(window, window.angular); diff --git a/app/vendor/angular/angular-sanitize.min.js b/app/vendor/angular/angular-sanitize.min.js new file mode 100644 index 00000000..ed3ec446 --- /dev/null +++ b/app/vendor/angular/angular-sanitize.min.js @@ -0,0 +1,14 @@ +/* + AngularJS v1.2.3 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(n,h,q){'use strict';function F(a){var e=[];t(e,h.noop).chars(a);return e.join("")}function k(a){var e={};a=a.split(",");var d;for(d=0;d=c;d--)e.end&&e.end(f[d]);f.length=c}}var b,g,f=[],l=a;for(f.last=function(){return f[f.length-1]};a;){g=!0;if(f.last()&&y[f.last()])a=a.replace(RegExp("(.*)<\\s*\\/\\s*"+f.last()+"[^>]*>","i"),function(a,b){b=b.replace(I,"$1").replace(J,"$1");e.chars&&e.chars(r(b));return""}),c("",f.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(e.comment&&e.comment(a.substring(4,b)),a=a.substring(b+3),g=!1);else if(z.test(a)){if(b=a.match(z))a= +a.replace(b[0],""),g=!1}else if(K.test(a)){if(b=a.match(A))a=a.substring(b[0].length),b[0].replace(A,c),g=!1}else L.test(a)&&(b=a.match(B))&&(a=a.substring(b[0].length),b[0].replace(B,d),g=!1);g&&(b=a.indexOf("<"),g=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),e.chars&&e.chars(r(g)))}if(a==l)throw M("badparse",a);l=a}c()}function r(a){if(!a)return"";a=/^(\s*)([\s\S]*?)(\s*)$/.exec(a);a[0]="";a[2]&&(s.innerHTML=a[2].replace(//g,">")}function t(a,e){var d=!1,c=h.bind(a,a.push);return{start:function(a,g,f){a=h.lowercase(a);!d&&y[a]&&(d=a);d||!0!==D[a]||(c("<"),c(a),h.forEach(g,function(d,f){var g=h.lowercase(f),k="img"===a&&"src"===g||"background"===g;!0!==O[g]||!0===E[g]&&!e(d,k)||(c(" "),c(f),c('="'),c(C(d)),c('"'))}),c(f?"/>":">"))},end:function(a){a=h.lowercase(a);d||!0!==D[a]||(c(""));a==d&&(d=!1)},chars:function(a){d|| +c(C(a))}}}var M=h.$$minErr("$sanitize"),B=/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,A=/^<\s*\/\s*([\w:-]+)[^>]*>/,H=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,L=/^]*?)>/i,J=/]/,d=/^mailto:/;return function(c,b){function g(a){a&&m.push(F(a))}function f(a,c){m.push("');g(c);m.push("")}if(!c)return c;for(var l,k=c,m=[],p,n;l=k.match(e);)p=l[0],l[2]==l[3]&&(p="mailto:"+p),n=l.index,g(k.substr(0,n)),f(p,l[0].replace(d,"")),k=k.substring(n+l[0].length);g(k);return a(m.join(""))}}])})(window,window.angular); +//# sourceMappingURL=angular-sanitize.min.js.map diff --git a/app/vendor/angular/angular-sanitize.min.js.map b/app/vendor/angular/angular-sanitize.min.js.map new file mode 100644 index 00000000..f211e9a6 --- /dev/null +++ b/app/vendor/angular/angular-sanitize.min.js.map @@ -0,0 +1,8 @@ +{ +"version":3, +"file":"angular-sanitize.min.js", +"lineCount":13, +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAgJtCC,QAASA,EAAY,CAACC,CAAD,CAAQ,CAC3B,IAAIC,EAAM,EACGC,EAAAC,CAAmBF,CAAnBE,CAAwBN,CAAAO,KAAxBD,CACbH,MAAA,CAAaA,CAAb,CACA,OAAOC,EAAAI,KAAA,CAAS,EAAT,CAJoB,CAmE7BC,QAASA,EAAO,CAACC,CAAD,CAAM,CAAA,IAChBC,EAAM,EAAIC,EAAAA,CAAQF,CAAAG,MAAA,CAAU,GAAV,CAAtB,KAAsCC,CACtC,KAAKA,CAAL,CAAS,CAAT,CAAYA,CAAZ,CAAgBF,CAAAG,OAAhB,CAA8BD,CAAA,EAA9B,CAAmCH,CAAA,CAAIC,CAAA,CAAME,CAAN,CAAJ,CAAA,CAAgB,CAAA,CACnD,OAAOH,EAHa,CAmBtBK,QAASA,EAAU,CAAEC,CAAF,CAAQC,CAAR,CAAkB,CAiFnCC,QAASA,EAAa,CAAEC,CAAF,CAAOC,CAAP,CAAgBC,CAAhB,CAAsBC,CAAtB,CAA8B,CAClDF,CAAA,CAAUrB,CAAAwB,UAAA,CAAkBH,CAAlB,CACV,IAAKI,CAAA,CAAeJ,CAAf,CAAL,CACE,IAAA,CAAQK,CAAAC,KAAA,EAAR,EAAwBC,CAAA,CAAgBF,CAAAC,KAAA,EAAhB,CAAxB,CAAA,CACEE,CAAA,CAAa,EAAb,CAAiBH,CAAAC,KAAA,EAAjB,CAICG,EAAA,CAAwBT,CAAxB,CAAL,EAA0CK,CAAAC,KAAA,EAA1C,EAA0DN,CAA1D,EACEQ,CAAA,CAAa,EAAb,CAAiBR,CAAjB,CAKF,EAFAE,CAEA,CAFQQ,CAAA,CAAcV,CAAd,CAER,EAFmC,CAAC,CAACE,CAErC,GACEG,CAAAM,KAAA,CAAYX,CAAZ,CAEF,KAAIY,EAAQ,EAEZX,EAAAY,QAAA,CAAaC,CAAb,CACE,QAAQ,CAACC,CAAD,CAAQC,CAAR,CAAcC,CAAd,CAAiCC,CAAjC,CAAoDC,CAApD,CAAmE,CAMzEP,CAAA,CAAMI,CAAN,CAAA,CAAcI,CAAA,CALFH,CAKE,EAJTC,CAIS,EAHTC,CAGS,EAFT,EAES,CAN2D,CAD7E,CASItB,EAAAwB,MAAJ,EAAmBxB,CAAAwB,MAAA,CAAerB,CAAf,CAAwBY,CAAxB,CAA+BV,CAA/B,CA5B+B,CA+BpDM,QAASA,EAAW,CAAET,CAAF,CAAOC,CAAP,CAAiB,CAAA,IAC/BsB,EAAM,CADyB,CACtB7B,CAEb,IADAO,CACA,CADUrB,CAAAwB,UAAA,CAAkBH,CAAlB,CACV,CAEE,IAAMsB,CAAN,CAAYjB,CAAAX,OAAZ,CAA2B,CAA3B,CAAqC,CAArC,EAA8B4B,CAA9B,EACOjB,CAAA,CAAOiB,CAAP,CADP,EACuBtB,CADvB,CAAwCsB,CAAA,EAAxC;AAIF,GAAY,CAAZ,EAAKA,CAAL,CAAgB,CAEd,IAAM7B,CAAN,CAAUY,CAAAX,OAAV,CAAyB,CAAzB,CAA4BD,CAA5B,EAAiC6B,CAAjC,CAAsC7B,CAAA,EAAtC,CACMI,CAAA0B,IAAJ,EAAiB1B,CAAA0B,IAAA,CAAalB,CAAA,CAAOZ,CAAP,CAAb,CAGnBY,EAAAX,OAAA,CAAe4B,CAND,CATmB,CAhHF,IAC/BE,CAD+B,CACxB1C,CADwB,CACVuB,EAAQ,EADE,CACEC,EAAOV,CAG5C,KAFAS,CAAAC,KAEA,CAFamB,QAAQ,EAAG,CAAE,MAAOpB,EAAA,CAAOA,CAAAX,OAAP,CAAsB,CAAtB,CAAT,CAExB,CAAQE,CAAR,CAAA,CAAe,CACbd,CAAA,CAAQ,CAAA,CAGR,IAAMuB,CAAAC,KAAA,EAAN,EAAuBoB,CAAA,CAAiBrB,CAAAC,KAAA,EAAjB,CAAvB,CAmDEV,CASA,CATOA,CAAAiB,QAAA,CAAiBc,MAAJ,CAAW,kBAAX,CAAgCtB,CAAAC,KAAA,EAAhC,CAA+C,QAA/C,CAAyD,GAAzD,CAAb,CACL,QAAQ,CAACsB,CAAD,CAAMC,CAAN,CAAW,CACjBA,CAAA,CAAOA,CAAAhB,QAAA,CAAaiB,CAAb,CAA6B,IAA7B,CAAAjB,QAAA,CAA2CkB,CAA3C,CAAyD,IAAzD,CAEHlC,EAAAf,MAAJ,EAAmBe,CAAAf,MAAA,CAAesC,CAAA,CAAeS,CAAf,CAAf,CAEnB,OAAO,EALU,CADd,CASP,CAAArB,CAAA,CAAa,EAAb,CAAiBH,CAAAC,KAAA,EAAjB,CA5DF,KAAyD,CAGvD,GAA8B,CAA9B,GAAKV,CAAAoC,QAAA,CAAa,SAAb,CAAL,CAEER,CAEA,CAFQ5B,CAAAoC,QAAA,CAAa,IAAb,CAAmB,CAAnB,CAER,CAAc,CAAd,EAAKR,CAAL,EAAmB5B,CAAAqC,YAAA,CAAiB,QAAjB,CAAwBT,CAAxB,CAAnB,GAAsDA,CAAtD,GACM3B,CAAAqC,QAEJ,EAFqBrC,CAAAqC,QAAA,CAAiBtC,CAAAuC,UAAA,CAAgB,CAAhB,CAAmBX,CAAnB,CAAjB,CAErB,CADA5B,CACA,CADOA,CAAAuC,UAAA,CAAgBX,CAAhB,CAAwB,CAAxB,CACP,CAAA1C,CAAA,CAAQ,CAAA,CAHV,CAJF,KAUO,IAAKsD,CAAAC,KAAA,CAAoBzC,CAApB,CAAL,CAGL,IAFAmB,CAEA,CAFQnB,CAAAmB,MAAA,CAAYqB,CAAZ,CAER,CACExC,CACA;AADOA,CAAAiB,QAAA,CAAcE,CAAA,CAAM,CAAN,CAAd,CAAyB,EAAzB,CACP,CAAAjC,CAAA,CAAQ,CAAA,CAFV,CAHK,IAQA,IAAKwD,CAAAD,KAAA,CAA4BzC,CAA5B,CAAL,CAGL,IAFAmB,CAEA,CAFQnB,CAAAmB,MAAA,CAAYwB,CAAZ,CAER,CACE3C,CAEA,CAFOA,CAAAuC,UAAA,CAAgBpB,CAAA,CAAM,CAAN,CAAArB,OAAhB,CAEP,CADAqB,CAAA,CAAM,CAAN,CAAAF,QAAA,CAAkB0B,CAAlB,CAAkC/B,CAAlC,CACA,CAAA1B,CAAA,CAAQ,CAAA,CAHV,CAHK,IAUK0D,EAAAH,KAAA,CAAsBzC,CAAtB,CAAL,GACLmB,CADK,CACGnB,CAAAmB,MAAA,CAAY0B,CAAZ,CADH,IAIH7C,CAEA,CAFOA,CAAAuC,UAAA,CAAgBpB,CAAA,CAAM,CAAN,CAAArB,OAAhB,CAEP,CADAqB,CAAA,CAAM,CAAN,CAAAF,QAAA,CAAkB4B,CAAlB,CAAoC3C,CAApC,CACA,CAAAhB,CAAA,CAAQ,CAAA,CANL,CAUFA,EAAL,GACE0C,CAKA,CALQ5B,CAAAoC,QAAA,CAAa,GAAb,CAKR,CAHIH,CAGJ,CAHmB,CAAR,CAAAL,CAAA,CAAY5B,CAAZ,CAAmBA,CAAAuC,UAAA,CAAgB,CAAhB,CAAmBX,CAAnB,CAG9B,CAFA5B,CAEA,CAFe,CAAR,CAAA4B,CAAA,CAAY,EAAZ,CAAiB5B,CAAAuC,UAAA,CAAgBX,CAAhB,CAExB,CAAI3B,CAAAf,MAAJ,EAAmBe,CAAAf,MAAA,CAAesC,CAAA,CAAeS,CAAf,CAAf,CANrB,CAzCuD,CA+DzD,GAAKjC,CAAL,EAAaU,CAAb,CACE,KAAMoC,EAAA,CAAgB,UAAhB,CAC4C9C,CAD5C,CAAN,CAGFU,CAAA,CAAOV,CAvEM,CA2EfY,CAAA,EA/EmC,CA0IrCY,QAASA,EAAc,CAACuB,CAAD,CAAQ,CAC7B,GAAI,CAACA,CAAL,CACE,MAAO,EAILC,EAAAA,CADUC,wBACFC,KAAA,CAAaH,CAAb,CACZC,EAAA,CAAM,CAAN,CAAA,CAAW,EACPA,EAAA,CAAM,CAAN,CAAJ,GACEG,CAAAC,UACA,CADoBJ,CAAA,CAAM,CAAN,CAAA/B,QAAA,CAAiB,IAAjB,CAAsB,MAAtB,CACpB,CAAA+B,CAAA,CAAM,CAAN,CAAA,CAAWG,CAAAE,UAAX,EAAkCF,CAAAG,YAFpC,CAIA,OAAON,EAAAzD,KAAA,CAAW,EAAX,CAZsB,CAsB/BgE,QAASA,EAAc,CAACR,CAAD,CAAQ,CAC7B,MAAOA,EAAA9B,QAAA,CACG,IADH;AACS,OADT,CAAAA,QAAA,CAEGuC,CAFH,CAE4B,QAAQ,CAACT,CAAD,CAAO,CAC9C,MAAO,IAAP,CAAcA,CAAAU,WAAA,CAAiB,CAAjB,CAAd,CAAoC,GADU,CAF3C,CAAAxC,QAAA,CAKG,IALH,CAKS,MALT,CAAAA,QAAA,CAMG,IANH,CAMS,MANT,CADsB,CAoB/B7B,QAASA,EAAkB,CAACD,CAAD,CAAMuE,CAAN,CAAmB,CAC5C,IAAIC,EAAS,CAAA,CAAb,CACIC,EAAM7E,CAAA8E,KAAA,CAAa1E,CAAb,CAAkBA,CAAA4B,KAAlB,CACV,OAAO,OACEU,QAAQ,CAACtB,CAAD,CAAMa,CAAN,CAAaV,CAAb,CAAmB,CAChCH,CAAA,CAAMpB,CAAAwB,UAAA,CAAkBJ,CAAlB,CACDwD,EAAAA,CAAL,EAAe7B,CAAA,CAAgB3B,CAAhB,CAAf,GACEwD,CADF,CACWxD,CADX,CAGKwD,EAAL,EAAsC,CAAA,CAAtC,GAAeG,CAAA,CAAc3D,CAAd,CAAf,GACEyD,CAAA,CAAI,GAAJ,CAcA,CAbAA,CAAA,CAAIzD,CAAJ,CAaA,CAZApB,CAAAgF,QAAA,CAAgB/C,CAAhB,CAAuB,QAAQ,CAAC+B,CAAD,CAAQiB,CAAR,CAAY,CACzC,IAAIC,EAAKlF,CAAAwB,UAAA,CAAkByD,CAAlB,CAAT,CACIE,EAAmB,KAAnBA,GAAW/D,CAAX+D,EAAqC,KAArCA,GAA4BD,CAA5BC,EAAyD,YAAzDA,GAAgDD,CAC3B,EAAA,CAAzB,GAAIE,CAAA,CAAWF,CAAX,CAAJ,EACsB,CAAA,CADtB,GACGG,CAAA,CAASH,CAAT,CADH,EAC8B,CAAAP,CAAA,CAAaX,CAAb,CAAoBmB,CAApB,CAD9B,GAEEN,CAAA,CAAI,GAAJ,CAIA,CAHAA,CAAA,CAAII,CAAJ,CAGA,CAFAJ,CAAA,CAAI,IAAJ,CAEA,CADAA,CAAA,CAAIL,CAAA,CAAeR,CAAf,CAAJ,CACA,CAAAa,CAAA,CAAI,GAAJ,CANF,CAHyC,CAA3C,CAYA,CAAAA,CAAA,CAAItD,CAAA,CAAQ,IAAR,CAAe,GAAnB,CAfF,CALgC,CAD7B,KAwBAqB,QAAQ,CAACxB,CAAD,CAAK,CACdA,CAAA,CAAMpB,CAAAwB,UAAA,CAAkBJ,CAAlB,CACDwD,EAAL,EAAsC,CAAA,CAAtC,GAAeG,CAAA,CAAc3D,CAAd,CAAf,GACEyD,CAAA,CAAI,IAAJ,CAEA,CADAA,CAAA,CAAIzD,CAAJ,CACA,CAAAyD,CAAA,CAAI,GAAJ,CAHF,CAKIzD,EAAJ,EAAWwD,CAAX,GACEA,CADF,CACW,CAAA,CADX,CAPc,CAxBb,OAmCEzE,QAAQ,CAACA,CAAD,CAAO,CACbyE,CAAL;AACEC,CAAA,CAAIL,CAAA,CAAerE,CAAf,CAAJ,CAFgB,CAnCjB,CAHqC,CAxZ9C,IAAI4D,EAAkB/D,CAAAsF,SAAA,CAAiB,WAAjB,CAAtB,CAuJIxB,EACG,4FAxJP,CAyJEF,EAAiB,2BAzJnB,CA0JEzB,EAAc,yEA1JhB,CA2JE0B,EAAmB,IA3JrB,CA4JEF,EAAyB,SA5J3B,CA6JER,EAAiB,qBA7JnB,CA8JEM,EAAiB,qBA9JnB,CA+JEL,EAAe,yBA/JjB,CAiKEqB,EAA0B,gBAjK5B,CA0KI1C,EAAetB,CAAA,CAAQ,wBAAR,CAIf8E,EAAAA,CAA8B9E,CAAA,CAAQ,gDAAR,CAC9B+E,EAAAA,CAA+B/E,CAAA,CAAQ,OAAR,CADnC,KAEIqB,EAAyB9B,CAAAyF,OAAA,CAAe,EAAf,CACeD,CADf,CAEeD,CAFf,CAF7B,CAOI9D,EAAgBzB,CAAAyF,OAAA,CAAe,EAAf,CAAmBF,CAAnB,CAAgD9E,CAAA,CAAQ,4KAAR,CAAhD,CAPpB;AAYImB,EAAiB5B,CAAAyF,OAAA,CAAe,EAAf,CAAmBD,CAAnB,CAAiD/E,CAAA,CAAQ,2JAAR,CAAjD,CAZrB,CAkBIsC,EAAkBtC,CAAA,CAAQ,cAAR,CAlBtB,CAoBIsE,EAAgB/E,CAAAyF,OAAA,CAAe,EAAf,CACe1D,CADf,CAEeN,CAFf,CAGeG,CAHf,CAIeE,CAJf,CApBpB,CA2BIuD,EAAW5E,CAAA,CAAQ,0CAAR,CA3Bf,CA4BI2E,EAAapF,CAAAyF,OAAA,CAAe,EAAf,CAAmBJ,CAAnB,CAA6B5E,CAAA,CAC1C,oSAD0C,CAA7B,CA5BjB;AA+LI2D,EAAUsB,QAAAC,cAAA,CAAuB,KAAvB,CA2Fd3F,EAAA4F,OAAA,CAAe,YAAf,CAA6B,EAA7B,CAAAC,SAAA,CAA0C,WAA1C,CAtUAC,QAA0B,EAAG,CAC3B,IAAAC,KAAA,CAAY,CAAC,eAAD,CAAkB,QAAQ,CAACC,CAAD,CAAgB,CACpD,MAAO,SAAQ,CAAC/E,CAAD,CAAO,CACpB,IAAIb,EAAM,EACVY,EAAA,CAAWC,CAAX,CAAiBZ,CAAA,CAAmBD,CAAnB,CAAwB,QAAQ,CAAC6F,CAAD,CAAMd,CAAN,CAAe,CAC9D,MAAO,CAAC,SAAAzB,KAAA,CAAesC,CAAA,CAAcC,CAAd,CAAmBd,CAAnB,CAAf,CADsD,CAA/C,CAAjB,CAGA,OAAO/E,EAAAI,KAAA,CAAS,EAAT,CALa,CAD8B,CAA1C,CADe,CAsU7B,CAsGAR,EAAA4F,OAAA,CAAe,YAAf,CAAAM,OAAA,CAAoC,OAApC,CAA6C,CAAC,WAAD,CAAc,QAAQ,CAACC,CAAD,CAAY,CAAA,IACzEC,EACE,mEAFuE,CAGzEC,EAAgB,UAEpB,OAAO,SAAQ,CAACnD,CAAD,CAAOoD,CAAP,CAAe,CAoB5BC,QAASA,EAAO,CAACrD,CAAD,CAAO,CAChBA,CAAL,EAGAjC,CAAAe,KAAA,CAAU9B,CAAA,CAAagD,CAAb,CAAV,CAJqB,CAOvBsD,QAASA,EAAO,CAACC,CAAD,CAAMvD,CAAN,CAAY,CAC1BjC,CAAAe,KAAA,CAAU,KAAV,CACIhC,EAAA0G,UAAA,CAAkBJ,CAAlB,CAAJ,GACErF,CAAAe,KAAA,CAAU,UAAV,CAEA;AADAf,CAAAe,KAAA,CAAUsE,CAAV,CACA,CAAArF,CAAAe,KAAA,CAAU,IAAV,CAHF,CAKAf,EAAAe,KAAA,CAAU,QAAV,CACAf,EAAAe,KAAA,CAAUyE,CAAV,CACAxF,EAAAe,KAAA,CAAU,IAAV,CACAuE,EAAA,CAAQrD,CAAR,CACAjC,EAAAe,KAAA,CAAU,MAAV,CAX0B,CA1B5B,GAAI,CAACkB,CAAL,CAAW,MAAOA,EAMlB,KALA,IAAId,CAAJ,CACIuE,EAAMzD,CADV,CAEIjC,EAAO,EAFX,CAGIwF,CAHJ,CAII3F,CACJ,CAAQsB,CAAR,CAAgBuE,CAAAvE,MAAA,CAAUgE,CAAV,CAAhB,CAAA,CAEEK,CAMA,CANMrE,CAAA,CAAM,CAAN,CAMN,CAJIA,CAAA,CAAM,CAAN,CAIJ,EAJgBA,CAAA,CAAM,CAAN,CAIhB,GAJ0BqE,CAI1B,CAJgC,SAIhC,CAJ4CA,CAI5C,EAHA3F,CAGA,CAHIsB,CAAAS,MAGJ,CAFA0D,CAAA,CAAQI,CAAAC,OAAA,CAAW,CAAX,CAAc9F,CAAd,CAAR,CAEA,CADA0F,CAAA,CAAQC,CAAR,CAAarE,CAAA,CAAM,CAAN,CAAAF,QAAA,CAAiBmE,CAAjB,CAAgC,EAAhC,CAAb,CACA,CAAAM,CAAA,CAAMA,CAAAnD,UAAA,CAAc1C,CAAd,CAAkBsB,CAAA,CAAM,CAAN,CAAArB,OAAlB,CAERwF,EAAA,CAAQI,CAAR,CACA,OAAOR,EAAA,CAAUlF,CAAAT,KAAA,CAAU,EAAV,CAAV,CAlBqB,CAL+C,CAAlC,CAA7C,CAhjBsC,CAArC,CAAA,CAimBET,MAjmBF,CAimBUA,MAAAC,QAjmBV;", +"sources":["angular-sanitize.js"], +"names":["window","angular","undefined","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","makeMap","str","obj","items","split","i","length","htmlParser","html","handler","parseStartTag","tag","tagName","rest","unary","lowercase","blockElements","stack","last","inlineElements","parseEndTag","optionalEndTagElements","voidElements","push","attrs","replace","ATTR_REGEXP","match","name","doubleQuotedValue","singleQuotedValue","unquotedValue","decodeEntities","start","pos","end","index","stack.last","specialElements","RegExp","all","text","COMMENT_REGEXP","CDATA_REGEXP","indexOf","lastIndexOf","comment","substring","DOCTYPE_REGEXP","test","BEGING_END_TAGE_REGEXP","END_TAG_REGEXP","BEGIN_TAG_REGEXP","START_TAG_REGEXP","$sanitizeMinErr","value","parts","spaceRe","exec","hiddenPre","innerHTML","innerText","textContent","encodeEntities","NON_ALPHANUMERIC_REGEXP","charCodeAt","uriValidator","ignore","out","bind","validElements","forEach","key","lkey","isImage","validAttrs","uriAttrs","$$minErr","optionalEndTagBlockElements","optionalEndTagInlineElements","extend","document","createElement","module","provider","$SanitizeProvider","$get","$$sanitizeUri","uri","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","target","addText","addLink","url","isDefined","raw","substr"] +} diff --git a/app/vendor/angular/angular-touch.js b/app/vendor/angular/angular-touch.js new file mode 100644 index 00000000..cd45d0cf --- /dev/null +++ b/app/vendor/angular/angular-touch.js @@ -0,0 +1,563 @@ +/** + * @license AngularJS v1.2.3 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular, undefined) {'use strict'; + +/** + * @ngdoc overview + * @name ngTouch + * @description + * + * # ngTouch + * + * The `ngTouch` module provides touch events and other helpers for touch-enabled devices. + * The implementation is based on jQuery Mobile touch event handling + * ([jquerymobile.com](http://jquerymobile.com/)). + * + * {@installModule touch} + * + * See {@link ngTouch.$swipe `$swipe`} for usage. + * + *
+ * + */ + +// define ngTouch module +/* global -ngTouch */ +var ngTouch = angular.module('ngTouch', []); + +/* global ngTouch: false */ + + /** + * @ngdoc object + * @name ngTouch.$swipe + * + * @description + * The `$swipe` service is a service that abstracts the messier details of hold-and-drag swipe + * behavior, to make implementing swipe-related directives more convenient. + * + * Requires the {@link ngTouch `ngTouch`} module to be installed. + * + * `$swipe` is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngTouch`, and by + * `ngCarousel` in a separate component. + * + * # Usage + * The `$swipe` service is an object with a single method: `bind`. `bind` takes an element + * which is to be watched for swipes, and an object with four handler functions. See the + * documentation for `bind` below. + */ + +ngTouch.factory('$swipe', [function() { + // The total distance in any direction before we make the call on swipe vs. scroll. + var MOVE_BUFFER_RADIUS = 10; + + function getCoordinates(event) { + var touches = event.touches && event.touches.length ? event.touches : [event]; + var e = (event.changedTouches && event.changedTouches[0]) || + (event.originalEvent && event.originalEvent.changedTouches && + event.originalEvent.changedTouches[0]) || + touches[0].originalEvent || touches[0]; + + return { + x: e.clientX, + y: e.clientY + }; + } + + return { + /** + * @ngdoc method + * @name ngTouch.$swipe#bind + * @methodOf ngTouch.$swipe + * + * @description + * The main method of `$swipe`. It takes an element to be watched for swipe motions, and an + * object containing event handlers. + * + * The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end` + * receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }`. + * + * `start` is called on either `mousedown` or `touchstart`. After this event, `$swipe` is + * watching for `touchmove` or `mousemove` events. These events are ignored until the total + * distance moved in either dimension exceeds a small threshold. + * + * Once this threshold is exceeded, either the horizontal or vertical delta is greater. + * - If the horizontal distance is greater, this is a swipe and `move` and `end` events follow. + * - If the vertical distance is greater, this is a scroll, and we let the browser take over. + * A `cancel` event is sent. + * + * `move` is called on `mousemove` and `touchmove` after the above logic has determined that + * a swipe is in progress. + * + * `end` is called when a swipe is successfully completed with a `touchend` or `mouseup`. + * + * `cancel` is called either on a `touchcancel` from the browser, or when we begin scrolling + * as described above. + * + */ + bind: function(element, eventHandlers) { + // Absolute total movement, used to control swipe vs. scroll. + var totalX, totalY; + // Coordinates of the start position. + var startCoords; + // Last event's position. + var lastPos; + // Whether a swipe is active. + var active = false; + + element.on('touchstart mousedown', function(event) { + startCoords = getCoordinates(event); + active = true; + totalX = 0; + totalY = 0; + lastPos = startCoords; + eventHandlers['start'] && eventHandlers['start'](startCoords, event); + }); + + element.on('touchcancel', function(event) { + active = false; + eventHandlers['cancel'] && eventHandlers['cancel'](event); + }); + + element.on('touchmove mousemove', function(event) { + if (!active) return; + + // Android will send a touchcancel if it thinks we're starting to scroll. + // So when the total distance (+ or - or both) exceeds 10px in either direction, + // we either: + // - On totalX > totalY, we send preventDefault() and treat this as a swipe. + // - On totalY > totalX, we let the browser handle it as a scroll. + + if (!startCoords) return; + var coords = getCoordinates(event); + + totalX += Math.abs(coords.x - lastPos.x); + totalY += Math.abs(coords.y - lastPos.y); + + lastPos = coords; + + if (totalX < MOVE_BUFFER_RADIUS && totalY < MOVE_BUFFER_RADIUS) { + return; + } + + // One of totalX or totalY has exceeded the buffer, so decide on swipe vs. scroll. + if (totalY > totalX) { + // Allow native scrolling to take over. + active = false; + eventHandlers['cancel'] && eventHandlers['cancel'](event); + return; + } else { + // Prevent the browser from scrolling. + event.preventDefault(); + eventHandlers['move'] && eventHandlers['move'](coords, event); + } + }); + + element.on('touchend mouseup', function(event) { + if (!active) return; + active = false; + eventHandlers['end'] && eventHandlers['end'](getCoordinates(event), event); + }); + } + }; +}]); + +/* global ngTouch: false */ + +/** + * @ngdoc directive + * @name ngTouch.directive:ngClick + * + * @description + * A more powerful replacement for the default ngClick designed to be used on touchscreen + * devices. Most mobile browsers wait about 300ms after a tap-and-release before sending + * the click event. This version handles them immediately, and then prevents the + * following click event from propagating. + * + * Requires the {@link ngTouch `ngTouch`} module to be installed. + * + * This directive can fall back to using an ordinary click event, and so works on desktop + * browsers as well as mobile. + * + * This directive also sets the CSS class `ng-click-active` while the element is being held + * down (by a mouse click or touch) so you can restyle the depressed element if you wish. + * + * @element ANY + * @param {expression} ngClick {@link guide/expression Expression} to evaluate + * upon tap. (Event object is available as `$event`) + * + * @example + + + + count: {{ count }} + + + */ + +ngTouch.config(['$provide', function($provide) { + $provide.decorator('ngClickDirective', ['$delegate', function($delegate) { + // drop the default ngClick directive + $delegate.shift(); + return $delegate; + }]); +}]); + +ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement', + function($parse, $timeout, $rootElement) { + var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag. + var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers. + var PREVENT_DURATION = 2500; // 2.5 seconds maximum from preventGhostClick call to click + var CLICKBUSTER_THRESHOLD = 25; // 25 pixels in any dimension is the limit for busting clicks. + + var ACTIVE_CLASS_NAME = 'ng-click-active'; + var lastPreventedTime; + var touchCoordinates; + + + // TAP EVENTS AND GHOST CLICKS + // + // Why tap events? + // Mobile browsers detect a tap, then wait a moment (usually ~300ms) to see if you're + // double-tapping, and then fire a click event. + // + // This delay sucks and makes mobile apps feel unresponsive. + // So we detect touchstart, touchmove, touchcancel and touchend ourselves and determine when + // the user has tapped on something. + // + // What happens when the browser then generates a click event? + // The browser, of course, also detects the tap and fires a click after a delay. This results in + // tapping/clicking twice. So we do "clickbusting" to prevent it. + // + // How does it work? + // We attach global touchstart and click handlers, that run during the capture (early) phase. + // So the sequence for a tap is: + // - global touchstart: Sets an "allowable region" at the point touched. + // - element's touchstart: Starts a touch + // (- touchmove or touchcancel ends the touch, no click follows) + // - element's touchend: Determines if the tap is valid (didn't move too far away, didn't hold + // too long) and fires the user's tap handler. The touchend also calls preventGhostClick(). + // - preventGhostClick() removes the allowable region the global touchstart created. + // - The browser generates a click event. + // - The global click handler catches the click, and checks whether it was in an allowable region. + // - If preventGhostClick was called, the region will have been removed, the click is busted. + // - If the region is still there, the click proceeds normally. Therefore clicks on links and + // other elements without ngTap on them work normally. + // + // This is an ugly, terrible hack! + // Yeah, tell me about it. The alternatives are using the slow click events, or making our users + // deal with the ghost clicks, so I consider this the least of evils. Fortunately Angular + // encapsulates this ugly logic away from the user. + // + // Why not just put click handlers on the element? + // We do that too, just to be sure. The problem is that the tap event might have caused the DOM + // to change, so that the click fires in the same position but something else is there now. So + // the handlers are global and care only about coordinates and not elements. + + // Checks if the coordinates are close enough to be within the region. + function hit(x1, y1, x2, y2) { + return Math.abs(x1 - x2) < CLICKBUSTER_THRESHOLD && Math.abs(y1 - y2) < CLICKBUSTER_THRESHOLD; + } + + // Checks a list of allowable regions against a click location. + // Returns true if the click should be allowed. + // Splices out the allowable region from the list after it has been used. + function checkAllowableRegions(touchCoordinates, x, y) { + for (var i = 0; i < touchCoordinates.length; i += 2) { + if (hit(touchCoordinates[i], touchCoordinates[i+1], x, y)) { + touchCoordinates.splice(i, i + 2); + return true; // allowable region + } + } + return false; // No allowable region; bust it. + } + + // Global click handler that prevents the click if it's in a bustable zone and preventGhostClick + // was called recently. + function onClick(event) { + if (Date.now() - lastPreventedTime > PREVENT_DURATION) { + return; // Too old. + } + + var touches = event.touches && event.touches.length ? event.touches : [event]; + var x = touches[0].clientX; + var y = touches[0].clientY; + // Work around desktop Webkit quirk where clicking a label will fire two clicks (on the label + // and on the input element). Depending on the exact browser, this second click we don't want + // to bust has either (0,0) or negative coordinates. + if (x < 1 && y < 1) { + return; // offscreen + } + + // Look for an allowable region containing this click. + // If we find one, that means it was created by touchstart and not removed by + // preventGhostClick, so we don't bust it. + if (checkAllowableRegions(touchCoordinates, x, y)) { + return; + } + + // If we didn't find an allowable region, bust the click. + event.stopPropagation(); + event.preventDefault(); + + // Blur focused form elements + event.target && event.target.blur(); + } + + + // Global touchstart handler that creates an allowable region for a click event. + // This allowable region can be removed by preventGhostClick if we want to bust it. + function onTouchStart(event) { + var touches = event.touches && event.touches.length ? event.touches : [event]; + var x = touches[0].clientX; + var y = touches[0].clientY; + touchCoordinates.push(x, y); + + $timeout(function() { + // Remove the allowable region. + for (var i = 0; i < touchCoordinates.length; i += 2) { + if (touchCoordinates[i] == x && touchCoordinates[i+1] == y) { + touchCoordinates.splice(i, i + 2); + return; + } + } + }, PREVENT_DURATION, false); + } + + // On the first call, attaches some event handlers. Then whenever it gets called, it creates a + // zone around the touchstart where clicks will get busted. + function preventGhostClick(x, y) { + if (!touchCoordinates) { + $rootElement[0].addEventListener('click', onClick, true); + $rootElement[0].addEventListener('touchstart', onTouchStart, true); + touchCoordinates = []; + } + + lastPreventedTime = Date.now(); + + checkAllowableRegions(touchCoordinates, x, y); + } + + // Actual linking function. + return function(scope, element, attr) { + var clickHandler = $parse(attr.ngClick), + tapping = false, + tapElement, // Used to blur the element after a tap. + startTime, // Used to check if the tap was held too long. + touchStartX, + touchStartY; + + function resetState() { + tapping = false; + element.removeClass(ACTIVE_CLASS_NAME); + } + + element.on('touchstart', function(event) { + tapping = true; + tapElement = event.target ? event.target : event.srcElement; // IE uses srcElement. + // Hack for Safari, which can target text nodes instead of containers. + if(tapElement.nodeType == 3) { + tapElement = tapElement.parentNode; + } + + element.addClass(ACTIVE_CLASS_NAME); + + startTime = Date.now(); + + var touches = event.touches && event.touches.length ? event.touches : [event]; + var e = touches[0].originalEvent || touches[0]; + touchStartX = e.clientX; + touchStartY = e.clientY; + }); + + element.on('touchmove', function(event) { + resetState(); + }); + + element.on('touchcancel', function(event) { + resetState(); + }); + + element.on('touchend', function(event) { + var diff = Date.now() - startTime; + + var touches = (event.changedTouches && event.changedTouches.length) ? event.changedTouches : + ((event.touches && event.touches.length) ? event.touches : [event]); + var e = touches[0].originalEvent || touches[0]; + var x = e.clientX; + var y = e.clientY; + var dist = Math.sqrt( Math.pow(x - touchStartX, 2) + Math.pow(y - touchStartY, 2) ); + + if (tapping && diff < TAP_DURATION && dist < MOVE_TOLERANCE) { + // Call preventGhostClick so the clickbuster will catch the corresponding click. + preventGhostClick(x, y); + + // Blur the focused element (the button, probably) before firing the callback. + // This doesn't work perfectly on Android Chrome, but seems to work elsewhere. + // I couldn't get anything to work reliably on Android Chrome. + if (tapElement) { + tapElement.blur(); + } + + if (!angular.isDefined(attr.disabled) || attr.disabled === false) { + element.triggerHandler('click', [event]); + } + } + + resetState(); + }); + + // Hack for iOS Safari's benefit. It goes searching for onclick handlers and is liable to click + // something else nearby. + element.onclick = function(event) { }; + + // Actual click handler. + // There are three different kinds of clicks, only two of which reach this point. + // - On desktop browsers without touch events, their clicks will always come here. + // - On mobile browsers, the simulated "fast" click will call this. + // - But the browser's follow-up slow click will be "busted" before it reaches this handler. + // Therefore it's safe to use this directive on both mobile and desktop. + element.on('click', function(event, touchend) { + scope.$apply(function() { + clickHandler(scope, {$event: (touchend || event)}); + }); + }); + + element.on('mousedown', function(event) { + element.addClass(ACTIVE_CLASS_NAME); + }); + + element.on('mousemove mouseup', function(event) { + element.removeClass(ACTIVE_CLASS_NAME); + }); + + }; +}]); + +/* global ngTouch: false */ + +/** + * @ngdoc directive + * @name ngTouch.directive:ngSwipeLeft + * + * @description + * Specify custom behavior when an element is swiped to the left on a touchscreen device. + * A leftward swipe is a quick, right-to-left slide of the finger. + * Though ngSwipeLeft is designed for touch-based devices, it will work with a mouse click and drag + * too. + * + * Requires the {@link ngTouch `ngTouch`} module to be installed. + * + * @element ANY + * @param {expression} ngSwipeLeft {@link guide/expression Expression} to evaluate + * upon left swipe. (Event object is available as `$event`) + * + * @example + + +
+ Some list content, like an email in the inbox +
+
+ + +
+
+
+ */ + +/** + * @ngdoc directive + * @name ngTouch.directive:ngSwipeRight + * + * @description + * Specify custom behavior when an element is swiped to the right on a touchscreen device. + * A rightward swipe is a quick, left-to-right slide of the finger. + * Though ngSwipeRight is designed for touch-based devices, it will work with a mouse click and drag + * too. + * + * Requires the {@link ngTouch `ngTouch`} module to be installed. + * + * @element ANY + * @param {expression} ngSwipeRight {@link guide/expression Expression} to evaluate + * upon right swipe. (Event object is available as `$event`) + * + * @example + + +
+ Some list content, like an email in the inbox +
+
+ + +
+
+
+ */ + +function makeSwipeDirective(directiveName, direction, eventName) { + ngTouch.directive(directiveName, ['$parse', '$swipe', function($parse, $swipe) { + // The maximum vertical delta for a swipe should be less than 75px. + var MAX_VERTICAL_DISTANCE = 75; + // Vertical distance should not be more than a fraction of the horizontal distance. + var MAX_VERTICAL_RATIO = 0.3; + // At least a 30px lateral motion is necessary for a swipe. + var MIN_HORIZONTAL_DISTANCE = 30; + + return function(scope, element, attr) { + var swipeHandler = $parse(attr[directiveName]); + + var startCoords, valid; + + function validSwipe(coords) { + // Check that it's within the coordinates. + // Absolute vertical distance must be within tolerances. + // Horizontal distance, we take the current X - the starting X. + // This is negative for leftward swipes and positive for rightward swipes. + // After multiplying by the direction (-1 for left, +1 for right), legal swipes + // (ie. same direction as the directive wants) will have a positive delta and + // illegal ones a negative delta. + // Therefore this delta must be positive, and larger than the minimum. + if (!startCoords) return false; + var deltaY = Math.abs(coords.y - startCoords.y); + var deltaX = (coords.x - startCoords.x) * direction; + return valid && // Short circuit for already-invalidated swipes. + deltaY < MAX_VERTICAL_DISTANCE && + deltaX > 0 && + deltaX > MIN_HORIZONTAL_DISTANCE && + deltaY / deltaX < MAX_VERTICAL_RATIO; + } + + $swipe.bind(element, { + 'start': function(coords, event) { + startCoords = coords; + valid = true; + }, + 'cancel': function(event) { + valid = false; + }, + 'end': function(coords, event) { + if (validSwipe(coords)) { + scope.$apply(function() { + element.triggerHandler(eventName); + swipeHandler(scope, {$event: event}); + }); + } + } + }); + }; + }]); +} + +// Left is negative X-coordinate, right is positive. +makeSwipeDirective('ngSwipeLeft', -1, 'swipeleft'); +makeSwipeDirective('ngSwipeRight', 1, 'swiperight'); + + + +})(window, window.angular); diff --git a/app/vendor/angular/angular-touch.min.js b/app/vendor/angular/angular-touch.min.js new file mode 100644 index 00000000..9e554042 --- /dev/null +++ b/app/vendor/angular/angular-touch.min.js @@ -0,0 +1,13 @@ +/* + AngularJS v1.2.3 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(y,v,z){'use strict';function t(g,a,b){q.directive(g,["$parse","$swipe",function(l,n){var r=75,h=0.3,d=30;return function(p,m,k){function e(e){if(!u)return!1;var c=Math.abs(e.y-u.y);e=(e.x-u.x)*a;return f&&cd&&c/el&&10>n|| +(n>l?(d=!1,b.cancel&&b.cancel(a)):(a.preventDefault(),b.move&&b.move(m,a)))}});a.on("touchend mouseup",function(a){d&&(d=!1,b.end&&b.end(g(a),a))})}}}]);q.config(["$provide",function(g){g.decorator("ngClickDirective",["$delegate",function(a){a.shift();return a}])}]);q.directive("ngClick",["$parse","$timeout","$rootElement",function(g,a,b){function l(a,c,b){for(var f=0;fh)){var c= +a.touches&&a.touches.length?a.touches:[a],b=c[0].clientX,c=c[0].clientY;1>b&&1>c||l(k,b,c)||(a.stopPropagation(),a.preventDefault(),a.target&&a.target.blur())}}function r(b){b=b.touches&&b.touches.length?b.touches:[b];var c=b[0].clientX,d=b[0].clientY;k.push(c,d);a(function(){for(var a=0;ah&&12>p)&&(k||(b[0].addEventListener("click",n,!0),b[0].addEventListener("touchstart",r,!0),k=[]),m=Date.now(),l(k,e,g),s&&s.blur(),v.isDefined(d.disabled)&&!1!==d.disabled||c.triggerHandler("click",[a]));f()});c.onclick=function(a){};c.on("click",function(b,c){a.$apply(function(){h(a,{$event:c||b})})});c.on("mousedown",function(a){c.addClass(p)});c.on("mousemove mouseup",function(a){c.removeClass(p)})}}]);t("ngSwipeLeft",-1,"swipeleft");t("ngSwipeRight",1,"swiperight")})(window, +window.angular); +//# sourceMappingURL=angular-touch.min.js.map diff --git a/app/vendor/angular/angular-touch.min.js.map b/app/vendor/angular/angular-touch.min.js.map new file mode 100644 index 00000000..6681ba1b --- /dev/null +++ b/app/vendor/angular/angular-touch.min.js.map @@ -0,0 +1,8 @@ +{ +"version":3, +"file":"angular-touch.min.js", +"lineCount":12, +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAiftCC,QAASA,EAAkB,CAACC,CAAD,CAAgBC,CAAhB,CAA2BC,CAA3B,CAAsC,CAC/DC,CAAAC,UAAA,CAAkBJ,CAAlB,CAAiC,CAAC,QAAD,CAAW,QAAX,CAAqB,QAAQ,CAACK,CAAD,CAASC,CAAT,CAAiB,CAE7E,IAAIC,EAAwB,EAA5B,CAEIC,EAAqB,GAFzB,CAIIC,EAA0B,EAE9B,OAAO,SAAQ,CAACC,CAAD,CAAQC,CAAR,CAAiBC,CAAjB,CAAuB,CAKpCC,QAASA,EAAU,CAACC,CAAD,CAAS,CAS1B,GAAI,CAACC,CAAL,CAAkB,MAAO,CAAA,CACzB,KAAIC,EAASC,IAAAC,IAAA,CAASJ,CAAAK,EAAT,CAAoBJ,CAAAI,EAApB,CACTC,EAAAA,EAAUN,CAAAO,EAAVD,CAAqBL,CAAAM,EAArBD,EAAsCnB,CAC1C,OAAOqB,EAAP,EACIN,CADJ,CACaT,CADb,EAEa,CAFb,CAEIa,CAFJ,EAGIA,CAHJ,CAGaX,CAHb,EAIIO,CAJJ,CAIaI,CAJb,CAIsBZ,CAhBI,CAJ5B,IAAIe,EAAelB,CAAA,CAAOO,CAAA,CAAKZ,CAAL,CAAP,CAAnB,CAEIe,CAFJ,CAEiBO,CAqBjBhB,EAAAkB,KAAA,CAAYb,CAAZ,CAAqB,OACVc,QAAQ,CAACX,CAAD,CAASY,CAAT,CAAgB,CAC/BX,CAAA,CAAcD,CACdQ,EAAA,CAAQ,CAAA,CAFuB,CADd,QAKTK,QAAQ,CAACD,CAAD,CAAQ,CACxBJ,CAAA,CAAQ,CAAA,CADgB,CALP,KAQZM,QAAQ,CAACd,CAAD,CAASY,CAAT,CAAgB,CACzBb,CAAA,CAAWC,CAAX,CAAJ,EACEJ,CAAAmB,OAAA,CAAa,QAAQ,EAAG,CACtBlB,CAAAmB,eAAA,CAAuB5B,CAAvB,CACAqB,EAAA,CAAab,CAAb,CAAoB,QAASgB,CAAT,CAApB,CAFsB,CAAxB,CAF2B,CARZ,CAArB,CAxBoC,CARuC,CAA9C,CAAjC,CAD+D,CA1djE,IAAIvB,EAAUN,CAAAkC,OAAA,CAAe,SAAf,CAA0B,EAA1B,CAuBd5B,EAAA6B,QAAA,CAAgB,QAAhB,CAA0B,CAAC,QAAQ,EAAG,CAIpCC,QAASA,EAAc,CAACP,CAAD,CAAQ,CAC7B,IAAIQ,EAAUR,CAAAQ,QAAA,EAAiBR,CAAAQ,QAAAC,OAAjB;AAAwCT,CAAAQ,QAAxC,CAAwD,CAACR,CAAD,CAClEU,EAAAA,CAAKV,CAAAW,eAALD,EAA6BV,CAAAW,eAAA,CAAqB,CAArB,CAA7BD,EACCV,CAAAY,cADDF,EACwBV,CAAAY,cAAAD,eADxBD,EAEIV,CAAAY,cAAAD,eAAA,CAAmC,CAAnC,CAFJD,EAGAF,CAAA,CAAQ,CAAR,CAAAI,cAHAF,EAG4BF,CAAA,CAAQ,CAAR,CAEhC,OAAO,GACFE,CAAAG,QADE,GAEFH,CAAAI,QAFE,CAPsB,CAa/B,MAAO,MA+BChB,QAAQ,CAACb,CAAD,CAAU8B,CAAV,CAAyB,CAAA,IAEjCC,CAFiC,CAEzBC,CAFyB,CAIjC5B,CAJiC,CAMjC6B,CANiC,CAQjCC,EAAS,CAAA,CAEblC,EAAAmC,GAAA,CAAW,sBAAX,CAAmC,QAAQ,CAACpB,CAAD,CAAQ,CACjDX,CAAA,CAAckB,CAAA,CAAeP,CAAf,CACdmB,EAAA,CAAS,CAAA,CAETF,EAAA,CADAD,CACA,CADS,CAETE,EAAA,CAAU7B,CACV0B,EAAA,MAAA,EAA0BA,CAAA,MAAA,CAAuB1B,CAAvB,CAAoCW,CAApC,CANuB,CAAnD,CASAf,EAAAmC,GAAA,CAAW,aAAX,CAA0B,QAAQ,CAACpB,CAAD,CAAQ,CACxCmB,CAAA,CAAS,CAAA,CACTJ,EAAA,OAAA,EAA2BA,CAAA,OAAA,CAAwBf,CAAxB,CAFa,CAA1C,CAKAf,EAAAmC,GAAA,CAAW,qBAAX,CAAkC,QAAQ,CAACpB,CAAD,CAAQ,CAChD,GAAKmB,CAAL,EAQK9B,CARL,CAQA,CACA,IAAID,EAASmB,CAAA,CAAeP,CAAf,CAEbgB,EAAA,EAAUzB,IAAAC,IAAA,CAASJ,CAAAO,EAAT,CAAoBuB,CAAAvB,EAApB,CACVsB,EAAA,EAAU1B,IAAAC,IAAA,CAASJ,CAAAK,EAAT,CAAoByB,CAAAzB,EAApB,CAEVyB,EAAA,CAAU9B,CArFSiC,GAuFnB,CAAIL,CAAJ,EAvFmBK,EAuFnB,CAAmCJ,CAAnC;CAKIA,CAAJ,CAAaD,CAAb,EAEEG,CACA,CADS,CAAA,CACT,CAAAJ,CAAA,OAAA,EAA2BA,CAAA,OAAA,CAAwBf,CAAxB,CAH7B,GAOEA,CAAAsB,eAAA,EACA,CAAAP,CAAA,KAAA,EAAyBA,CAAA,KAAA,CAAsB3B,CAAtB,CAA8BY,CAA9B,CAR3B,CALA,CARA,CATgD,CAAlD,CAkCAf,EAAAmC,GAAA,CAAW,kBAAX,CAA+B,QAAQ,CAACpB,CAAD,CAAQ,CACxCmB,CAAL,GACAA,CACA,CADS,CAAA,CACT,CAAAJ,CAAA,IAAA,EAAwBA,CAAA,IAAA,CAAqBR,CAAA,CAAeP,CAAf,CAArB,CAA4CA,CAA5C,CAFxB,CAD6C,CAA/C,CA1DqC,CA/BlC,CAjB6B,CAAZ,CAA1B,CAsJAvB,EAAA8C,OAAA,CAAe,CAAC,UAAD,CAAa,QAAQ,CAACC,CAAD,CAAW,CAC7CA,CAAAC,UAAA,CAAmB,kBAAnB,CAAuC,CAAC,WAAD,CAAc,QAAQ,CAACC,CAAD,CAAY,CAEvEA,CAAAC,MAAA,EACA,OAAOD,EAHgE,CAAlC,CAAvC,CAD6C,CAAhC,CAAf,CAQAjD,EAAAC,UAAA,CAAkB,SAAlB,CAA6B,CAAC,QAAD,CAAW,UAAX,CAAuB,cAAvB,CACzB,QAAQ,CAACC,CAAD,CAASiD,CAAT,CAAmBC,CAAnB,CAAiC,CA0D3CC,QAASA,EAAqB,CAACC,CAAD,CAAmBpC,CAAnB,CAAsBF,CAAtB,CAAyB,CACrD,IAAK,IAAIuC,EAAI,CAAb,CAAgBA,CAAhB,CAAoBD,CAAAtB,OAApB,CAA6CuB,CAA7C,EAAkD,CAAlD,CACE,GARKzC,IAAAC,IAAA,CAQGuC,CAAAE,CAAiBD,CAAjBC,CARH,CAQ+CtC,CAR/C,CAQL,CARyBuC,CAQzB,EARkD3C,IAAAC,IAAA,CAQrBuC,CAAAI,CAAiBH,CAAjBG,CAAmB,CAAnBA,CARqB,CAQK1C,CARL,CAQlD,CARsEyC,CAQtE,CAEE,MADAH,EAAAK,OAAA,CAAwBJ,CAAxB,CAA2BA,CAA3B,CAA+B,CAA/B,CACO,CAAA,CAAA,CAGX,OAAO,CAAA,CAP8C,CAYvDK,QAASA,EAAO,CAACrC,CAAD,CAAQ,CACtB,GAAI,EAAAsC,IAAAC,IAAA,EAAA,CAAaC,CAAb,CAAiCC,CAAjC,CAAJ,CAAA,CAIA,IAAIjC;AAAUR,CAAAQ,QAAA,EAAiBR,CAAAQ,QAAAC,OAAjB,CAAwCT,CAAAQ,QAAxC,CAAwD,CAACR,CAAD,CAAtE,CACIL,EAAIa,CAAA,CAAQ,CAAR,CAAAK,QADR,CAEIpB,EAAIe,CAAA,CAAQ,CAAR,CAAAM,QAIA,EAAR,CAAInB,CAAJ,EAAiB,CAAjB,CAAaF,CAAb,EAOIqC,CAAA,CAAsBC,CAAtB,CAAwCpC,CAAxC,CAA2CF,CAA3C,CAPJ,GAYAO,CAAA0C,gBAAA,EAIA,CAHA1C,CAAAsB,eAAA,EAGA,CAAAtB,CAAA2C,OAAA,EAAgB3C,CAAA2C,OAAAC,KAAA,EAhBhB,CAVA,CADsB,CAiCxBC,QAASA,EAAY,CAAC7C,CAAD,CAAQ,CACvBQ,CAAAA,CAAUR,CAAAQ,QAAA,EAAiBR,CAAAQ,QAAAC,OAAjB,CAAwCT,CAAAQ,QAAxC,CAAwD,CAACR,CAAD,CACtE,KAAIL,EAAIa,CAAA,CAAQ,CAAR,CAAAK,QAAR,CACIpB,EAAIe,CAAA,CAAQ,CAAR,CAAAM,QACRiB,EAAAe,KAAA,CAAsBnD,CAAtB,CAAyBF,CAAzB,CAEAmC,EAAA,CAAS,QAAQ,EAAG,CAElB,IAAK,IAAII,EAAI,CAAb,CAAgBA,CAAhB,CAAoBD,CAAAtB,OAApB,CAA6CuB,CAA7C,EAAkD,CAAlD,CACE,GAAID,CAAA,CAAiBC,CAAjB,CAAJ,EAA2BrC,CAA3B,EAAgCoC,CAAA,CAAiBC,CAAjB,CAAmB,CAAnB,CAAhC,EAAyDvC,CAAzD,CAA4D,CAC1DsC,CAAAK,OAAA,CAAwBJ,CAAxB,CAA2BA,CAA3B,CAA+B,CAA/B,CACA,MAF0D,CAH5C,CAApB,CAQGS,CARH,CAQqB,CAAA,CARrB,CAN2B,CApG7B,IAAIA,EAAmB,IAAvB,CACIP,EAAwB,EAD5B,CAGIa,EAAoB,iBAHxB,CAIIP,CAJJ,CAKIT,CA+HJ,OAAO,SAAQ,CAAC/C,CAAD,CAAQC,CAAR,CAAiBC,CAAjB,CAAuB,CAQpC8D,QAASA,EAAU,EAAG,CACpBC,CAAA,CAAU,CAAA,CACVhE,EAAAiE,YAAA,CAAoBH,CAApB,CAFoB,CARc,IAChCI,EAAexE,CAAA,CAAOO,CAAAkE,QAAP,CADiB,CAEhCH,EAAU,CAAA,CAFsB,CAGhCI,CAHgC,CAIhCC,CAJgC,CAKhCC,CALgC,CAMhCC,CAOJvE,EAAAmC,GAAA,CAAW,YAAX;AAAyB,QAAQ,CAACpB,CAAD,CAAQ,CACvCiD,CAAA,CAAU,CAAA,CACVI,EAAA,CAAarD,CAAA2C,OAAA,CAAe3C,CAAA2C,OAAf,CAA8B3C,CAAAyD,WAEjB,EAA1B,EAAGJ,CAAAK,SAAH,GACEL,CADF,CACeA,CAAAM,WADf,CAIA1E,EAAA2E,SAAA,CAAiBb,CAAjB,CAEAO,EAAA,CAAYhB,IAAAC,IAAA,EAER/B,EAAAA,CAAUR,CAAAQ,QAAA,EAAiBR,CAAAQ,QAAAC,OAAjB,CAAwCT,CAAAQ,QAAxC,CAAwD,CAACR,CAAD,CAClEU,EAAAA,CAAIF,CAAA,CAAQ,CAAR,CAAAI,cAAJF,EAAgCF,CAAA,CAAQ,CAAR,CACpC+C,EAAA,CAAc7C,CAAAG,QACd2C,EAAA,CAAc9C,CAAAI,QAfyB,CAAzC,CAkBA7B,EAAAmC,GAAA,CAAW,WAAX,CAAwB,QAAQ,CAACpB,CAAD,CAAQ,CACtCgD,CAAA,EADsC,CAAxC,CAIA/D,EAAAmC,GAAA,CAAW,aAAX,CAA0B,QAAQ,CAACpB,CAAD,CAAQ,CACxCgD,CAAA,EADwC,CAA1C,CAIA/D,EAAAmC,GAAA,CAAW,UAAX,CAAuB,QAAQ,CAACpB,CAAD,CAAQ,CACrC,IAAI6D,EAAOvB,IAAAC,IAAA,EAAPsB,CAAoBP,CAAxB,CAEI9C,EAAWR,CAAAW,eAAD,EAAyBX,CAAAW,eAAAF,OAAzB,CAAwDT,CAAAW,eAAxD,CACRX,CAAAQ,QAAD,EAAkBR,CAAAQ,QAAAC,OAAlB,CAA0CT,CAAAQ,QAA1C,CAA0D,CAACR,CAAD,CAH/D,CAIIU,EAAIF,CAAA,CAAQ,CAAR,CAAAI,cAAJF,EAAgCF,CAAA,CAAQ,CAAR,CAJpC,CAKIb,EAAIe,CAAAG,QALR,CAMIpB,EAAIiB,CAAAI,QANR,CAOIgD,EAAOvE,IAAAwE,KAAA,CAAWxE,IAAAyE,IAAA,CAASrE,CAAT;AAAa4D,CAAb,CAA0B,CAA1B,CAAX,CAA0ChE,IAAAyE,IAAA,CAASvE,CAAT,CAAa+D,CAAb,CAA0B,CAA1B,CAA1C,CAEPP,EAAJ,GAvLegB,GAuLf,CAAeJ,CAAf,EAtLiBK,EAsLjB,CAAsCJ,CAAtC,IA7DG/B,CAwED,GAvEFF,CAAA,CAAa,CAAb,CAAAsC,iBAAA,CAAiC,OAAjC,CAA0C9B,CAA1C,CAAmD,CAAA,CAAnD,CAEA,CADAR,CAAA,CAAa,CAAb,CAAAsC,iBAAA,CAAiC,YAAjC,CAA+CtB,CAA/C,CAA6D,CAAA,CAA7D,CACA,CAAAd,CAAA,CAAmB,EAqEjB,EAlEJS,CAkEI,CAlEgBF,IAAAC,IAAA,EAkEhB,CAhEJT,CAAA,CAAsBC,CAAtB,CAuDsBpC,CAvDtB,CAuDyBF,CAvDzB,CAgEI,CAJI4D,CAIJ,EAHEA,CAAAT,KAAA,EAGF,CAAKzE,CAAAiG,UAAA,CAAkBlF,CAAAmF,SAAlB,CAAL,EAA2D,CAAA,CAA3D,GAAyCnF,CAAAmF,SAAzC,EACEpF,CAAAmB,eAAA,CAAuB,OAAvB,CAAgC,CAACJ,CAAD,CAAhC,CAZJ,CAgBAgD,EAAA,EA1BqC,CAAvC,CA+BA/D,EAAAqF,QAAA,CAAkBC,QAAQ,CAACvE,CAAD,CAAQ,EAQlCf,EAAAmC,GAAA,CAAW,OAAX,CAAoB,QAAQ,CAACpB,CAAD,CAAQwE,CAAR,CAAkB,CAC5CxF,CAAAmB,OAAA,CAAa,QAAQ,EAAG,CACtBgD,CAAA,CAAanE,CAAb,CAAoB,QAAUwF,CAAV,EAAsBxE,CAAtB,CAApB,CADsB,CAAxB,CAD4C,CAA9C,CAMAf,EAAAmC,GAAA,CAAW,WAAX,CAAwB,QAAQ,CAACpB,CAAD,CAAQ,CACtCf,CAAA2E,SAAA,CAAiBb,CAAjB,CADsC,CAAxC,CAIA9D,EAAAmC,GAAA,CAAW,mBAAX,CAAgC,QAAQ,CAACpB,CAAD,CAAQ,CAC9Cf,CAAAiE,YAAA,CAAoBH,CAApB,CAD8C,CAAhD,CAxFoC,CAvIK,CADhB,CAA7B,CA4VA1E,EAAA,CAAmB,aAAnB,CAAmC,EAAnC,CAAsC,WAAtC,CACAA,EAAA,CAAmB,cAAnB,CAAmC,CAAnC,CAAsC,YAAtC,CAziBsC,CAArC,CAAA,CA6iBEH,MA7iBF;AA6iBUA,MAAAC,QA7iBV;", +"sources":["angular-touch.js"], +"names":["window","angular","undefined","makeSwipeDirective","directiveName","direction","eventName","ngTouch","directive","$parse","$swipe","MAX_VERTICAL_DISTANCE","MAX_VERTICAL_RATIO","MIN_HORIZONTAL_DISTANCE","scope","element","attr","validSwipe","coords","startCoords","deltaY","Math","abs","y","deltaX","x","valid","swipeHandler","bind","start","event","cancel","end","$apply","triggerHandler","module","factory","getCoordinates","touches","length","e","changedTouches","originalEvent","clientX","clientY","eventHandlers","totalX","totalY","lastPos","active","on","MOVE_BUFFER_RADIUS","preventDefault","config","$provide","decorator","$delegate","shift","$timeout","$rootElement","checkAllowableRegions","touchCoordinates","i","x1","CLICKBUSTER_THRESHOLD","y1","splice","onClick","Date","now","lastPreventedTime","PREVENT_DURATION","stopPropagation","target","blur","onTouchStart","push","ACTIVE_CLASS_NAME","resetState","tapping","removeClass","clickHandler","ngClick","tapElement","startTime","touchStartX","touchStartY","srcElement","nodeType","parentNode","addClass","diff","dist","sqrt","pow","TAP_DURATION","MOVE_TOLERANCE","addEventListener","isDefined","disabled","onclick","element.onclick","touchend"] +} diff --git a/app/vendor/angular/angular.js b/app/vendor/angular/angular.js new file mode 100644 index 00000000..8b538ce2 --- /dev/null +++ b/app/vendor/angular/angular.js @@ -0,0 +1,20282 @@ +/** + * @license AngularJS v1.2.3 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, document, undefined) {'use strict'; + +/** + * @description + * + * This object provides a utility for producing rich Error messages within + * Angular. It can be called as follows: + * + * var exampleMinErr = minErr('example'); + * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); + * + * The above creates an instance of minErr in the example namespace. The + * resulting error will have a namespaced error code of example.one. The + * resulting error will replace {0} with the value of foo, and {1} with the + * value of bar. The object is not restricted in the number of arguments it can + * take. + * + * If fewer arguments are specified than necessary for interpolation, the extra + * interpolation markers will be preserved in the final string. + * + * Since data will be parsed statically during a build step, some restrictions + * are applied with respect to how minErr instances are created and called. + * Instances should have names of the form namespaceMinErr for a minErr created + * using minErr('namespace') . Error codes, namespaces and template strings + * should all be static strings, not variables or general expressions. + * + * @param {string} module The namespace to use for the new minErr instance. + * @returns {function(string, string, ...): Error} instance + */ + +function minErr(module) { + return function () { + var code = arguments[0], + prefix = '[' + (module ? module + ':' : '') + code + '] ', + template = arguments[1], + templateArgs = arguments, + stringify = function (obj) { + if (typeof obj === 'function') { + return obj.toString().replace(/ \{[\s\S]*$/, ''); + } else if (typeof obj === 'undefined') { + return 'undefined'; + } else if (typeof obj !== 'string') { + return JSON.stringify(obj); + } + return obj; + }, + message, i; + + message = prefix + template.replace(/\{\d+\}/g, function (match) { + var index = +match.slice(1, -1), arg; + + if (index + 2 < templateArgs.length) { + arg = templateArgs[index + 2]; + if (typeof arg === 'function') { + return arg.toString().replace(/ ?\{[\s\S]*$/, ''); + } else if (typeof arg === 'undefined') { + return 'undefined'; + } else if (typeof arg !== 'string') { + return toJson(arg); + } + return arg; + } + return match; + }); + + message = message + '\nhttp://errors.angularjs.org/1.2.3/' + + (module ? module + '/' : '') + code; + for (i = 2; i < arguments.length; i++) { + message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + + encodeURIComponent(stringify(arguments[i])); + } + + return new Error(message); + }; +} + +/* We need to tell jshint what variables are being exported */ +/* global + -angular, + -msie, + -jqLite, + -jQuery, + -slice, + -push, + -toString, + -ngMinErr, + -_angular, + -angularModule, + -nodeName_, + -uid, + + -lowercase, + -uppercase, + -manualLowercase, + -manualUppercase, + -nodeName_, + -isArrayLike, + -forEach, + -sortedKeys, + -forEachSorted, + -reverseParams, + -nextUid, + -setHashKey, + -extend, + -int, + -inherit, + -noop, + -identity, + -valueFn, + -isUndefined, + -isDefined, + -isObject, + -isString, + -isNumber, + -isDate, + -isArray, + -isFunction, + -isRegExp, + -isWindow, + -isScope, + -isFile, + -isBoolean, + -trim, + -isElement, + -makeMap, + -map, + -size, + -includes, + -indexOf, + -arrayRemove, + -isLeafNode, + -copy, + -shallowCopy, + -equals, + -csp, + -concat, + -sliceArgs, + -bind, + -toJsonReplacer, + -toJson, + -fromJson, + -toBoolean, + -startingTag, + -tryDecodeURIComponent, + -parseKeyValue, + -toKeyValue, + -encodeUriSegment, + -encodeUriQuery, + -angularInit, + -bootstrap, + -snake_case, + -bindJQuery, + -assertArg, + -assertArgFn, + -assertNotHasOwnProperty, + -getter, + -getBlockElements, + +*/ + +//////////////////////////////////// + +/** + * @ngdoc function + * @name angular.lowercase + * @function + * + * @description Converts the specified string to lowercase. + * @param {string} string String to be converted to lowercase. + * @returns {string} Lowercased string. + */ +var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;}; + + +/** + * @ngdoc function + * @name angular.uppercase + * @function + * + * @description Converts the specified string to uppercase. + * @param {string} string String to be converted to uppercase. + * @returns {string} Uppercased string. + */ +var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;}; + + +var manualLowercase = function(s) { + /* jshint bitwise: false */ + return isString(s) + ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) + : s; +}; +var manualUppercase = function(s) { + /* jshint bitwise: false */ + return isString(s) + ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) + : s; +}; + + +// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish +// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods +// with correct but slower alternatives. +if ('i' !== 'I'.toLowerCase()) { + lowercase = manualLowercase; + uppercase = manualUppercase; +} + + +var /** holds major version number for IE or NaN for real browsers */ + msie, + jqLite, // delay binding since jQuery could be loaded after us. + jQuery, // delay binding + slice = [].slice, + push = [].push, + toString = Object.prototype.toString, + ngMinErr = minErr('ng'), + + + _angular = window.angular, + /** @name angular */ + angular = window.angular || (window.angular = {}), + angularModule, + nodeName_, + uid = ['0', '0', '0']; + +/** + * IE 11 changed the format of the UserAgent string. + * See http://msdn.microsoft.com/en-us/library/ms537503.aspx + */ +msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]); +if (isNaN(msie)) { + msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]); +} + + +/** + * @private + * @param {*} obj + * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, + * String ...) + */ +function isArrayLike(obj) { + if (obj == null || isWindow(obj)) { + return false; + } + + var length = obj.length; + + if (obj.nodeType === 1 && length) { + return true; + } + + return isString(obj) || isArray(obj) || length === 0 || + typeof length === 'number' && length > 0 && (length - 1) in obj; +} + +/** + * @ngdoc function + * @name angular.forEach + * @function + * + * @description + * Invokes the `iterator` function once for each item in `obj` collection, which can be either an + * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value` + * is the value of an object property or an array element and `key` is the object property key or + * array element index. Specifying a `context` for the function is optional. + * + * Note: this function was previously known as `angular.foreach`. + * +
+     var values = {name: 'misko', gender: 'male'};
+     var log = [];
+     angular.forEach(values, function(value, key){
+       this.push(key + ': ' + value);
+     }, log);
+     expect(log).toEqual(['name: misko', 'gender:male']);
+   
+ * + * @param {Object|Array} obj Object to iterate over. + * @param {Function} iterator Iterator function. + * @param {Object=} context Object to become context (`this`) for the iterator function. + * @returns {Object|Array} Reference to `obj`. + */ +function forEach(obj, iterator, context) { + var key; + if (obj) { + if (isFunction(obj)){ + for (key in obj) { + if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) { + iterator.call(context, obj[key], key); + } + } + } else if (obj.forEach && obj.forEach !== forEach) { + obj.forEach(iterator, context); + } else if (isArrayLike(obj)) { + for (key = 0; key < obj.length; key++) + iterator.call(context, obj[key], key); + } else { + for (key in obj) { + if (obj.hasOwnProperty(key)) { + iterator.call(context, obj[key], key); + } + } + } + } + return obj; +} + +function sortedKeys(obj) { + var keys = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + keys.push(key); + } + } + return keys.sort(); +} + +function forEachSorted(obj, iterator, context) { + var keys = sortedKeys(obj); + for ( var i = 0; i < keys.length; i++) { + iterator.call(context, obj[keys[i]], keys[i]); + } + return keys; +} + + +/** + * when using forEach the params are value, key, but it is often useful to have key, value. + * @param {function(string, *)} iteratorFn + * @returns {function(*, string)} + */ +function reverseParams(iteratorFn) { + return function(value, key) { iteratorFn(key, value); }; +} + +/** + * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric + * characters such as '012ABC'. The reason why we are not using simply a number counter is that + * the number string gets longer over time, and it can also overflow, where as the nextId + * will grow much slower, it is a string, and it will never overflow. + * + * @returns an unique alpha-numeric string + */ +function nextUid() { + var index = uid.length; + var digit; + + while(index) { + index--; + digit = uid[index].charCodeAt(0); + if (digit == 57 /*'9'*/) { + uid[index] = 'A'; + return uid.join(''); + } + if (digit == 90 /*'Z'*/) { + uid[index] = '0'; + } else { + uid[index] = String.fromCharCode(digit + 1); + return uid.join(''); + } + } + uid.unshift('0'); + return uid.join(''); +} + + +/** + * Set or clear the hashkey for an object. + * @param obj object + * @param h the hashkey (!truthy to delete the hashkey) + */ +function setHashKey(obj, h) { + if (h) { + obj.$$hashKey = h; + } + else { + delete obj.$$hashKey; + } +} + +/** + * @ngdoc function + * @name angular.extend + * @function + * + * @description + * Extends the destination object `dst` by copying all of the properties from the `src` object(s) + * to `dst`. You can specify multiple `src` objects. + * + * @param {Object} dst Destination object. + * @param {...Object} src Source object(s). + * @returns {Object} Reference to `dst`. + */ +function extend(dst) { + var h = dst.$$hashKey; + forEach(arguments, function(obj){ + if (obj !== dst) { + forEach(obj, function(value, key){ + dst[key] = value; + }); + } + }); + + setHashKey(dst,h); + return dst; +} + +function int(str) { + return parseInt(str, 10); +} + + +function inherit(parent, extra) { + return extend(new (extend(function() {}, {prototype:parent}))(), extra); +} + +/** + * @ngdoc function + * @name angular.noop + * @function + * + * @description + * A function that performs no operations. This function can be useful when writing code in the + * functional style. +
+     function foo(callback) {
+       var result = calculateResult();
+       (callback || angular.noop)(result);
+     }
+   
+ */ +function noop() {} +noop.$inject = []; + + +/** + * @ngdoc function + * @name angular.identity + * @function + * + * @description + * A function that returns its first argument. This function is useful when writing code in the + * functional style. + * +
+     function transformer(transformationFn, value) {
+       return (transformationFn || angular.identity)(value);
+     };
+   
+ */ +function identity($) {return $;} +identity.$inject = []; + + +function valueFn(value) {return function() {return value;};} + +/** + * @ngdoc function + * @name angular.isUndefined + * @function + * + * @description + * Determines if a reference is undefined. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is undefined. + */ +function isUndefined(value){return typeof value == 'undefined';} + + +/** + * @ngdoc function + * @name angular.isDefined + * @function + * + * @description + * Determines if a reference is defined. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is defined. + */ +function isDefined(value){return typeof value != 'undefined';} + + +/** + * @ngdoc function + * @name angular.isObject + * @function + * + * @description + * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not + * considered to be objects. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is an `Object` but not `null`. + */ +function isObject(value){return value != null && typeof value == 'object';} + + +/** + * @ngdoc function + * @name angular.isString + * @function + * + * @description + * Determines if a reference is a `String`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `String`. + */ +function isString(value){return typeof value == 'string';} + + +/** + * @ngdoc function + * @name angular.isNumber + * @function + * + * @description + * Determines if a reference is a `Number`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `Number`. + */ +function isNumber(value){return typeof value == 'number';} + + +/** + * @ngdoc function + * @name angular.isDate + * @function + * + * @description + * Determines if a value is a date. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `Date`. + */ +function isDate(value){ + return toString.apply(value) == '[object Date]'; +} + + +/** + * @ngdoc function + * @name angular.isArray + * @function + * + * @description + * Determines if a reference is an `Array`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is an `Array`. + */ +function isArray(value) { + return toString.apply(value) == '[object Array]'; +} + + +/** + * @ngdoc function + * @name angular.isFunction + * @function + * + * @description + * Determines if a reference is a `Function`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `Function`. + */ +function isFunction(value){return typeof value == 'function';} + + +/** + * Determines if a value is a regular expression object. + * + * @private + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `RegExp`. + */ +function isRegExp(value) { + return toString.apply(value) == '[object RegExp]'; +} + + +/** + * Checks if `obj` is a window object. + * + * @private + * @param {*} obj Object to check + * @returns {boolean} True if `obj` is a window obj. + */ +function isWindow(obj) { + return obj && obj.document && obj.location && obj.alert && obj.setInterval; +} + + +function isScope(obj) { + return obj && obj.$evalAsync && obj.$watch; +} + + +function isFile(obj) { + return toString.apply(obj) === '[object File]'; +} + + +function isBoolean(value) { + return typeof value == 'boolean'; +} + + +var trim = (function() { + // native trim is way faster: http://jsperf.com/angular-trim-test + // but IE doesn't have it... :-( + // TODO: we should move this into IE/ES5 polyfill + if (!String.prototype.trim) { + return function(value) { + return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value; + }; + } + return function(value) { + return isString(value) ? value.trim() : value; + }; +})(); + + +/** + * @ngdoc function + * @name angular.isElement + * @function + * + * @description + * Determines if a reference is a DOM element (or wrapped jQuery element). + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element). + */ +function isElement(node) { + return node && + (node.nodeName // we are a direct element + || (node.on && node.find)); // we have an on and find method part of jQuery API +} + +/** + * @param str 'key1,key2,...' + * @returns {object} in the form of {key1:true, key2:true, ...} + */ +function makeMap(str){ + var obj = {}, items = str.split(","), i; + for ( i = 0; i < items.length; i++ ) + obj[ items[i] ] = true; + return obj; +} + + +if (msie < 9) { + nodeName_ = function(element) { + element = element.nodeName ? element : element[0]; + return (element.scopeName && element.scopeName != 'HTML') + ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName; + }; +} else { + nodeName_ = function(element) { + return element.nodeName ? element.nodeName : element[0].nodeName; + }; +} + + +function map(obj, iterator, context) { + var results = []; + forEach(obj, function(value, index, list) { + results.push(iterator.call(context, value, index, list)); + }); + return results; +} + + +/** + * @description + * Determines the number of elements in an array, the number of properties an object has, or + * the length of a string. + * + * Note: This function is used to augment the Object type in Angular expressions. See + * {@link angular.Object} for more information about Angular arrays. + * + * @param {Object|Array|string} obj Object, array, or string to inspect. + * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object + * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array. + */ +function size(obj, ownPropsOnly) { + var count = 0, key; + + if (isArray(obj) || isString(obj)) { + return obj.length; + } else if (isObject(obj)){ + for (key in obj) + if (!ownPropsOnly || obj.hasOwnProperty(key)) + count++; + } + + return count; +} + + +function includes(array, obj) { + return indexOf(array, obj) != -1; +} + +function indexOf(array, obj) { + if (array.indexOf) return array.indexOf(obj); + + for ( var i = 0; i < array.length; i++) { + if (obj === array[i]) return i; + } + return -1; +} + +function arrayRemove(array, value) { + var index = indexOf(array, value); + if (index >=0) + array.splice(index, 1); + return value; +} + +function isLeafNode (node) { + if (node) { + switch (node.nodeName) { + case "OPTION": + case "PRE": + case "TITLE": + return true; + } + } + return false; +} + +/** + * @ngdoc function + * @name angular.copy + * @function + * + * @description + * Creates a deep copy of `source`, which should be an object or an array. + * + * * If no destination is supplied, a copy of the object or array is created. + * * If a destination is provided, all of its elements (for array) or properties (for objects) + * are deleted and then all elements/properties from the source are copied to it. + * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned. + * * If `source` is identical to 'destination' an exception will be thrown. + * + * @param {*} source The source that will be used to make a copy. + * Can be any type, including primitives, `null`, and `undefined`. + * @param {(Object|Array)=} destination Destination into which the source is copied. If + * provided, must be of the same type as `source`. + * @returns {*} The copy or updated `destination`, if `destination` was specified. + * + * @example + + +
+
+ Name:
+ E-mail:
+ Gender: male + female
+ + +
+
form = {{user | json}}
+
master = {{master | json}}
+
+ + +
+
+ */ +function copy(source, destination){ + if (isWindow(source) || isScope(source)) { + throw ngMinErr('cpws', + "Can't copy! Making copies of Window or Scope instances is not supported."); + } + + if (!destination) { + destination = source; + if (source) { + if (isArray(source)) { + destination = copy(source, []); + } else if (isDate(source)) { + destination = new Date(source.getTime()); + } else if (isRegExp(source)) { + destination = new RegExp(source.source); + } else if (isObject(source)) { + destination = copy(source, {}); + } + } + } else { + if (source === destination) throw ngMinErr('cpi', + "Can't copy! Source and destination are identical."); + if (isArray(source)) { + destination.length = 0; + for ( var i = 0; i < source.length; i++) { + destination.push(copy(source[i])); + } + } else { + var h = destination.$$hashKey; + forEach(destination, function(value, key){ + delete destination[key]; + }); + for ( var key in source) { + destination[key] = copy(source[key]); + } + setHashKey(destination,h); + } + } + return destination; +} + +/** + * Create a shallow copy of an object + */ +function shallowCopy(src, dst) { + dst = dst || {}; + + for(var key in src) { + // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src + // so we don't need to worry hasOwnProperty here + if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') { + dst[key] = src[key]; + } + } + + return dst; +} + + +/** + * @ngdoc function + * @name angular.equals + * @function + * + * @description + * Determines if two objects or two values are equivalent. Supports value types, regular + * expressions, arrays and objects. + * + * Two objects or values are considered equivalent if at least one of the following is true: + * + * * Both objects or values pass `===` comparison. + * * Both objects or values are of the same type and all of their properties are equal by + * comparing them with `angular.equals`. + * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal) + * * Both values represent the same regular expression (In JavasScript, + * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual + * representation matches). + * + * During a property comparison, properties of `function` type and properties with names + * that begin with `$` are ignored. + * + * Scope and DOMWindow objects are being compared only by identify (`===`). + * + * @param {*} o1 Object or value to compare. + * @param {*} o2 Object or value to compare. + * @returns {boolean} True if arguments are equal. + */ +function equals(o1, o2) { + if (o1 === o2) return true; + if (o1 === null || o2 === null) return false; + if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN + var t1 = typeof o1, t2 = typeof o2, length, key, keySet; + if (t1 == t2) { + if (t1 == 'object') { + if (isArray(o1)) { + if (!isArray(o2)) return false; + if ((length = o1.length) == o2.length) { + for(key=0; key 2 ? sliceArgs(arguments, 2) : []; + if (isFunction(fn) && !(fn instanceof RegExp)) { + return curryArgs.length + ? function() { + return arguments.length + ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0))) + : fn.apply(self, curryArgs); + } + : function() { + return arguments.length + ? fn.apply(self, arguments) + : fn.call(self); + }; + } else { + // in IE, native methods are not functions so they cannot be bound (note: they don't need to be) + return fn; + } +} + + +function toJsonReplacer(key, value) { + var val = value; + + if (typeof key === 'string' && key.charAt(0) === '$') { + val = undefined; + } else if (isWindow(value)) { + val = '$WINDOW'; + } else if (value && document === value) { + val = '$DOCUMENT'; + } else if (isScope(value)) { + val = '$SCOPE'; + } + + return val; +} + + +/** + * @ngdoc function + * @name angular.toJson + * @function + * + * @description + * Serializes input into a JSON-formatted string. Properties with leading $ characters will be + * stripped since angular uses this notation internally. + * + * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON. + * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace. + * @returns {string|undefined} JSON-ified string representing `obj`. + */ +function toJson(obj, pretty) { + if (typeof obj === 'undefined') return undefined; + return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null); +} + + +/** + * @ngdoc function + * @name angular.fromJson + * @function + * + * @description + * Deserializes a JSON string. + * + * @param {string} json JSON string to deserialize. + * @returns {Object|Array|Date|string|number} Deserialized thingy. + */ +function fromJson(json) { + return isString(json) + ? JSON.parse(json) + : json; +} + + +function toBoolean(value) { + if (value && value.length !== 0) { + var v = lowercase("" + value); + value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]'); + } else { + value = false; + } + return value; +} + +/** + * @returns {string} Returns the string representation of the element. + */ +function startingTag(element) { + element = jqLite(element).clone(); + try { + // turns out IE does not let you set .html() on elements which + // are not allowed to have children. So we just ignore it. + element.html(''); + } catch(e) {} + // As Per DOM Standards + var TEXT_NODE = 3; + var elemHtml = jqLite('
').append(element).html(); + try { + return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) : + elemHtml. + match(/^(<[^>]+>)/)[1]. + replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); }); + } catch(e) { + return lowercase(elemHtml); + } + +} + + +///////////////////////////////////////////////// + +/** + * Tries to decode the URI component without throwing an exception. + * + * @private + * @param str value potential URI component to check. + * @returns {boolean} True if `value` can be decoded + * with the decodeURIComponent function. + */ +function tryDecodeURIComponent(value) { + try { + return decodeURIComponent(value); + } catch(e) { + // Ignore any invalid uri component + } +} + + +/** + * Parses an escaped url query string into key-value pairs. + * @returns Object.<(string|boolean)> + */ +function parseKeyValue(/**string*/keyValue) { + var obj = {}, key_value, key; + forEach((keyValue || "").split('&'), function(keyValue){ + if ( keyValue ) { + key_value = keyValue.split('='); + key = tryDecodeURIComponent(key_value[0]); + if ( isDefined(key) ) { + var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true; + if (!obj[key]) { + obj[key] = val; + } else if(isArray(obj[key])) { + obj[key].push(val); + } else { + obj[key] = [obj[key],val]; + } + } + } + }); + return obj; +} + +function toKeyValue(obj) { + var parts = []; + forEach(obj, function(value, key) { + if (isArray(value)) { + forEach(value, function(arrayValue) { + parts.push(encodeUriQuery(key, true) + + (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true))); + }); + } else { + parts.push(encodeUriQuery(key, true) + + (value === true ? '' : '=' + encodeUriQuery(value, true))); + } + }); + return parts.length ? parts.join('&') : ''; +} + + +/** + * We need our custom method because encodeURIComponent is too aggressive and doesn't follow + * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path + * segments: + * segment = *pchar + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * pct-encoded = "%" HEXDIG HEXDIG + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ +function encodeUriSegment(val) { + return encodeUriQuery(val, true). + replace(/%26/gi, '&'). + replace(/%3D/gi, '='). + replace(/%2B/gi, '+'); +} + + +/** + * This method is intended for encoding *key* or *value* parts of query component. We need a custom + * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be + * encoded per http://tools.ietf.org/html/rfc3986: + * query = *( pchar / "/" / "?" ) + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * pct-encoded = "%" HEXDIG HEXDIG + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ +function encodeUriQuery(val, pctEncodeSpaces) { + return encodeURIComponent(val). + replace(/%40/gi, '@'). + replace(/%3A/gi, ':'). + replace(/%24/g, '$'). + replace(/%2C/gi, ','). + replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); +} + + +/** + * @ngdoc directive + * @name ng.directive:ngApp + * + * @element ANY + * @param {angular.Module} ngApp an optional application + * {@link angular.module module} name to load. + * + * @description + * + * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive + * designates the **root element** of the application and is typically placed near the root element + * of the page - e.g. on the `` or `` tags. + * + * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp` + * found in the document will be used to define the root element to auto-bootstrap as an + * application. To run multiple applications in an HTML document you must manually bootstrap them using + * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other. + * + * You can specify an **AngularJS module** to be used as the root module for the application. This + * module will be loaded into the {@link AUTO.$injector} when the application is bootstrapped and + * should contain the application code needed or have dependencies on other modules that will + * contain the code. See {@link angular.module} for more information. + * + * In the example below if the `ngApp` directive were not placed on the `html` element then the + * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}` + * would not be resolved to `3`. + * + * `ngApp` is the easiest, and most common, way to bootstrap an application. + * + + +
+ I can add: {{a}} + {{b}} = {{ a+b }} + + + angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) { + $scope.a = 1; + $scope.b = 2; + }); + + + * + */ +function angularInit(element, bootstrap) { + var elements = [element], + appElement, + module, + names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'], + NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/; + + function append(element) { + element && elements.push(element); + } + + forEach(names, function(name) { + names[name] = true; + append(document.getElementById(name)); + name = name.replace(':', '\\:'); + if (element.querySelectorAll) { + forEach(element.querySelectorAll('.' + name), append); + forEach(element.querySelectorAll('.' + name + '\\:'), append); + forEach(element.querySelectorAll('[' + name + ']'), append); + } + }); + + forEach(elements, function(element) { + if (!appElement) { + var className = ' ' + element.className + ' '; + var match = NG_APP_CLASS_REGEXP.exec(className); + if (match) { + appElement = element; + module = (match[2] || '').replace(/\s+/g, ','); + } else { + forEach(element.attributes, function(attr) { + if (!appElement && names[attr.name]) { + appElement = element; + module = attr.value; + } + }); + } + } + }); + if (appElement) { + bootstrap(appElement, module ? [module] : []); + } +} + +/** + * @ngdoc function + * @name angular.bootstrap + * @description + * Use this function to manually start up angular application. + * + * See: {@link guide/bootstrap Bootstrap} + * + * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually. + * They must use {@link api/ng.directive:ngApp ngApp}. + * + * @param {Element} element DOM element which is the root of angular application. + * @param {Array=} modules an array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * See: {@link angular.module modules} + * @returns {AUTO.$injector} Returns the newly created injector for this app. + */ +function bootstrap(element, modules) { + var doBootstrap = function() { + element = jqLite(element); + + if (element.injector()) { + var tag = (element[0] === document) ? 'document' : startingTag(element); + throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag); + } + + modules = modules || []; + modules.unshift(['$provide', function($provide) { + $provide.value('$rootElement', element); + }]); + modules.unshift('ng'); + var injector = createInjector(modules); + injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate', + function(scope, element, compile, injector, animate) { + scope.$apply(function() { + element.data('$injector', injector); + compile(element)(scope); + }); + }] + ); + return injector; + }; + + var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; + + if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { + return doBootstrap(); + } + + window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); + angular.resumeBootstrap = function(extraModules) { + forEach(extraModules, function(module) { + modules.push(module); + }); + doBootstrap(); + }; +} + +var SNAKE_CASE_REGEXP = /[A-Z]/g; +function snake_case(name, separator){ + separator = separator || '_'; + return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) { + return (pos ? separator : '') + letter.toLowerCase(); + }); +} + +function bindJQuery() { + // bind to jQuery if present; + jQuery = window.jQuery; + // reset to jQuery or default to us. + if (jQuery) { + jqLite = jQuery; + extend(jQuery.fn, { + scope: JQLitePrototype.scope, + isolateScope: JQLitePrototype.isolateScope, + controller: JQLitePrototype.controller, + injector: JQLitePrototype.injector, + inheritedData: JQLitePrototype.inheritedData + }); + // Method signature: + // jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) + jqLitePatchJQueryRemove('remove', true, true, false); + jqLitePatchJQueryRemove('empty', false, false, false); + jqLitePatchJQueryRemove('html', false, false, true); + } else { + jqLite = JQLite; + } + angular.element = jqLite; +} + +/** + * throw error if the argument is falsy. + */ +function assertArg(arg, name, reason) { + if (!arg) { + throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required")); + } + return arg; +} + +function assertArgFn(arg, name, acceptArrayAnnotation) { + if (acceptArrayAnnotation && isArray(arg)) { + arg = arg[arg.length - 1]; + } + + assertArg(isFunction(arg), name, 'not a function, got ' + + (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg)); + return arg; +} + +/** + * throw error if the name given is hasOwnProperty + * @param {String} name the name to test + * @param {String} context the context in which the name is used, such as module or directive + */ +function assertNotHasOwnProperty(name, context) { + if (name === 'hasOwnProperty') { + throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context); + } +} + +/** + * Return the value accessible from the object by path. Any undefined traversals are ignored + * @param {Object} obj starting object + * @param {string} path path to traverse + * @param {boolean=true} bindFnToScope + * @returns value as accessible by path + */ +//TODO(misko): this function needs to be removed +function getter(obj, path, bindFnToScope) { + if (!path) return obj; + var keys = path.split('.'); + var key; + var lastInstance = obj; + var len = keys.length; + + for (var i = 0; i < len; i++) { + key = keys[i]; + if (obj) { + obj = (lastInstance = obj)[key]; + } + } + if (!bindFnToScope && isFunction(obj)) { + return bind(lastInstance, obj); + } + return obj; +} + +/** + * Return the siblings between `startNode` and `endNode`, inclusive + * @param {Object} object with `startNode` and `endNode` properties + * @returns jQlite object containing the elements + */ +function getBlockElements(block) { + if (block.startNode === block.endNode) { + return jqLite(block.startNode); + } + + var element = block.startNode; + var elements = [element]; + + do { + element = element.nextSibling; + if (!element) break; + elements.push(element); + } while (element !== block.endNode); + + return jqLite(elements); +} + +/** + * @ngdoc interface + * @name angular.Module + * @description + * + * Interface for configuring angular {@link angular.module modules}. + */ + +function setupModuleLoader(window) { + + var $injectorMinErr = minErr('$injector'); + var ngMinErr = minErr('ng'); + + function ensure(obj, name, factory) { + return obj[name] || (obj[name] = factory()); + } + + var angular = ensure(window, 'angular', Object); + + // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap + angular.$$minErr = angular.$$minErr || minErr; + + return ensure(angular, 'module', function() { + /** @type {Object.} */ + var modules = {}; + + /** + * @ngdoc function + * @name angular.module + * @description + * + * The `angular.module` is a global place for creating, registering and retrieving Angular + * modules. + * All modules (angular core or 3rd party) that should be available to an application must be + * registered using this mechanism. + * + * When passed two or more arguments, a new module is created. If passed only one argument, an + * existing module (the name passed as the first argument to `module`) is retrieved. + * + * + * # Module + * + * A module is a collection of services, directives, filters, and configuration information. + * `angular.module` is used to configure the {@link AUTO.$injector $injector}. + * + *
+     * // Create a new module
+     * var myModule = angular.module('myModule', []);
+     *
+     * // register a new service
+     * myModule.value('appName', 'MyCoolApp');
+     *
+     * // configure existing services inside initialization blocks.
+     * myModule.config(function($locationProvider) {
+     *   // Configure existing providers
+     *   $locationProvider.hashPrefix('!');
+     * });
+     * 
+ * + * Then you can create an injector and load your modules like this: + * + *
+     * var injector = angular.injector(['ng', 'MyModule'])
+     * 
+ * + * However it's more likely that you'll just use + * {@link ng.directive:ngApp ngApp} or + * {@link angular.bootstrap} to simplify this process for you. + * + * @param {!string} name The name of the module to create or retrieve. + * @param {Array.=} requires If specified then new module is being created. If + * unspecified then the the module is being retrieved for further configuration. + * @param {Function} configFn Optional configuration function for the module. Same as + * {@link angular.Module#methods_config Module#config()}. + * @returns {module} new module with the {@link angular.Module} api. + */ + return function module(name, requires, configFn) { + var assertNotHasOwnProperty = function(name, context) { + if (name === 'hasOwnProperty') { + throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); + } + }; + + assertNotHasOwnProperty(name, 'module'); + if (requires && modules.hasOwnProperty(name)) { + modules[name] = null; + } + return ensure(modules, name, function() { + if (!requires) { + throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " + + "the module name or forgot to load it. If registering a module ensure that you " + + "specify the dependencies as the second argument.", name); + } + + /** @type {!Array.>} */ + var invokeQueue = []; + + /** @type {!Array.} */ + var runBlocks = []; + + var config = invokeLater('$injector', 'invoke'); + + /** @type {angular.Module} */ + var moduleInstance = { + // Private state + _invokeQueue: invokeQueue, + _runBlocks: runBlocks, + + /** + * @ngdoc property + * @name angular.Module#requires + * @propertyOf angular.Module + * @returns {Array.} List of module names which must be loaded before this module. + * @description + * Holds the list of modules which the injector will load before the current module is + * loaded. + */ + requires: requires, + + /** + * @ngdoc property + * @name angular.Module#name + * @propertyOf angular.Module + * @returns {string} Name of the module. + * @description + */ + name: name, + + + /** + * @ngdoc method + * @name angular.Module#provider + * @methodOf angular.Module + * @param {string} name service name + * @param {Function} providerType Construction function for creating new instance of the + * service. + * @description + * See {@link AUTO.$provide#provider $provide.provider()}. + */ + provider: invokeLater('$provide', 'provider'), + + /** + * @ngdoc method + * @name angular.Module#factory + * @methodOf angular.Module + * @param {string} name service name + * @param {Function} providerFunction Function for creating new instance of the service. + * @description + * See {@link AUTO.$provide#factory $provide.factory()}. + */ + factory: invokeLater('$provide', 'factory'), + + /** + * @ngdoc method + * @name angular.Module#service + * @methodOf angular.Module + * @param {string} name service name + * @param {Function} constructor A constructor function that will be instantiated. + * @description + * See {@link AUTO.$provide#service $provide.service()}. + */ + service: invokeLater('$provide', 'service'), + + /** + * @ngdoc method + * @name angular.Module#value + * @methodOf angular.Module + * @param {string} name service name + * @param {*} object Service instance object. + * @description + * See {@link AUTO.$provide#value $provide.value()}. + */ + value: invokeLater('$provide', 'value'), + + /** + * @ngdoc method + * @name angular.Module#constant + * @methodOf angular.Module + * @param {string} name constant name + * @param {*} object Constant value. + * @description + * Because the constant are fixed, they get applied before other provide methods. + * See {@link AUTO.$provide#constant $provide.constant()}. + */ + constant: invokeLater('$provide', 'constant', 'unshift'), + + /** + * @ngdoc method + * @name angular.Module#animation + * @methodOf angular.Module + * @param {string} name animation name + * @param {Function} animationFactory Factory function for creating new instance of an + * animation. + * @description + * + * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. + * + * + * Defines an animation hook that can be later used with + * {@link ngAnimate.$animate $animate} service and directives that use this service. + * + *
+           * module.animation('.animation-name', function($inject1, $inject2) {
+           *   return {
+           *     eventName : function(element, done) {
+           *       //code to run the animation
+           *       //once complete, then run done()
+           *       return function cancellationFunction(element) {
+           *         //code to cancel the animation
+           *       }
+           *     }
+           *   }
+           * })
+           * 
+ * + * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and + * {@link ngAnimate ngAnimate module} for more information. + */ + animation: invokeLater('$animateProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#filter + * @methodOf angular.Module + * @param {string} name Filter name. + * @param {Function} filterFactory Factory function for creating new instance of filter. + * @description + * See {@link ng.$filterProvider#register $filterProvider.register()}. + */ + filter: invokeLater('$filterProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#controller + * @methodOf angular.Module + * @param {string|Object} name Controller name, or an object map of controllers where the + * keys are the names and the values are the constructors. + * @param {Function} constructor Controller constructor function. + * @description + * See {@link ng.$controllerProvider#register $controllerProvider.register()}. + */ + controller: invokeLater('$controllerProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#directive + * @methodOf angular.Module + * @param {string|Object} name Directive name, or an object map of directives where the + * keys are the names and the values are the factories. + * @param {Function} directiveFactory Factory function for creating new instance of + * directives. + * @description + * See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}. + */ + directive: invokeLater('$compileProvider', 'directive'), + + /** + * @ngdoc method + * @name angular.Module#config + * @methodOf angular.Module + * @param {Function} configFn Execute this function on module load. Useful for service + * configuration. + * @description + * Use this method to register work which needs to be performed on module loading. + */ + config: config, + + /** + * @ngdoc method + * @name angular.Module#run + * @methodOf angular.Module + * @param {Function} initializationFn Execute this function after injector creation. + * Useful for application initialization. + * @description + * Use this method to register work which should be performed when the injector is done + * loading all modules. + */ + run: function(block) { + runBlocks.push(block); + return this; + } + }; + + if (configFn) { + config(configFn); + } + + return moduleInstance; + + /** + * @param {string} provider + * @param {string} method + * @param {String=} insertMethod + * @returns {angular.Module} + */ + function invokeLater(provider, method, insertMethod) { + return function() { + invokeQueue[insertMethod || 'push']([provider, method, arguments]); + return moduleInstance; + }; + } + }); + }; + }); + +} + +/* global + angularModule: true, + version: true, + + $LocaleProvider, + $CompileProvider, + + htmlAnchorDirective, + inputDirective, + inputDirective, + formDirective, + scriptDirective, + selectDirective, + styleDirective, + optionDirective, + ngBindDirective, + ngBindHtmlDirective, + ngBindTemplateDirective, + ngClassDirective, + ngClassEvenDirective, + ngClassOddDirective, + ngCspDirective, + ngCloakDirective, + ngControllerDirective, + ngFormDirective, + ngHideDirective, + ngIfDirective, + ngIncludeDirective, + ngInitDirective, + ngNonBindableDirective, + ngPluralizeDirective, + ngRepeatDirective, + ngShowDirective, + ngStyleDirective, + ngSwitchDirective, + ngSwitchWhenDirective, + ngSwitchDefaultDirective, + ngOptionsDirective, + ngTranscludeDirective, + ngModelDirective, + ngListDirective, + ngChangeDirective, + requiredDirective, + requiredDirective, + ngValueDirective, + ngAttributeAliasDirectives, + ngEventDirectives, + + $AnchorScrollProvider, + $AnimateProvider, + $BrowserProvider, + $CacheFactoryProvider, + $ControllerProvider, + $DocumentProvider, + $ExceptionHandlerProvider, + $FilterProvider, + $InterpolateProvider, + $IntervalProvider, + $HttpProvider, + $HttpBackendProvider, + $LocationProvider, + $LogProvider, + $ParseProvider, + $RootScopeProvider, + $QProvider, + $$SanitizeUriProvider, + $SceProvider, + $SceDelegateProvider, + $SnifferProvider, + $TemplateCacheProvider, + $TimeoutProvider, + $WindowProvider +*/ + + +/** + * @ngdoc property + * @name angular.version + * @description + * An object that contains information about the current AngularJS version. This object has the + * following properties: + * + * - `full` – `{string}` – Full version string, such as "0.9.18". + * - `major` – `{number}` – Major version number, such as "0". + * - `minor` – `{number}` – Minor version number, such as "9". + * - `dot` – `{number}` – Dot version number, such as "18". + * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". + */ +var version = { + full: '1.2.3', // all of these placeholder strings will be replaced by grunt's + major: 1, // package task + minor: 2, + dot: 3, + codeName: 'unicorn-zapper' +}; + + +function publishExternalAPI(angular){ + extend(angular, { + 'bootstrap': bootstrap, + 'copy': copy, + 'extend': extend, + 'equals': equals, + 'element': jqLite, + 'forEach': forEach, + 'injector': createInjector, + 'noop':noop, + 'bind':bind, + 'toJson': toJson, + 'fromJson': fromJson, + 'identity':identity, + 'isUndefined': isUndefined, + 'isDefined': isDefined, + 'isString': isString, + 'isFunction': isFunction, + 'isObject': isObject, + 'isNumber': isNumber, + 'isElement': isElement, + 'isArray': isArray, + 'version': version, + 'isDate': isDate, + 'lowercase': lowercase, + 'uppercase': uppercase, + 'callbacks': {counter: 0}, + '$$minErr': minErr, + '$$csp': csp + }); + + angularModule = setupModuleLoader(window); + try { + angularModule('ngLocale'); + } catch (e) { + angularModule('ngLocale', []).provider('$locale', $LocaleProvider); + } + + angularModule('ng', ['ngLocale'], ['$provide', + function ngModule($provide) { + // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it. + $provide.provider({ + $$sanitizeUri: $$SanitizeUriProvider + }); + $provide.provider('$compile', $CompileProvider). + directive({ + a: htmlAnchorDirective, + input: inputDirective, + textarea: inputDirective, + form: formDirective, + script: scriptDirective, + select: selectDirective, + style: styleDirective, + option: optionDirective, + ngBind: ngBindDirective, + ngBindHtml: ngBindHtmlDirective, + ngBindTemplate: ngBindTemplateDirective, + ngClass: ngClassDirective, + ngClassEven: ngClassEvenDirective, + ngClassOdd: ngClassOddDirective, + ngCloak: ngCloakDirective, + ngController: ngControllerDirective, + ngForm: ngFormDirective, + ngHide: ngHideDirective, + ngIf: ngIfDirective, + ngInclude: ngIncludeDirective, + ngInit: ngInitDirective, + ngNonBindable: ngNonBindableDirective, + ngPluralize: ngPluralizeDirective, + ngRepeat: ngRepeatDirective, + ngShow: ngShowDirective, + ngStyle: ngStyleDirective, + ngSwitch: ngSwitchDirective, + ngSwitchWhen: ngSwitchWhenDirective, + ngSwitchDefault: ngSwitchDefaultDirective, + ngOptions: ngOptionsDirective, + ngTransclude: ngTranscludeDirective, + ngModel: ngModelDirective, + ngList: ngListDirective, + ngChange: ngChangeDirective, + required: requiredDirective, + ngRequired: requiredDirective, + ngValue: ngValueDirective + }). + directive(ngAttributeAliasDirectives). + directive(ngEventDirectives); + $provide.provider({ + $anchorScroll: $AnchorScrollProvider, + $animate: $AnimateProvider, + $browser: $BrowserProvider, + $cacheFactory: $CacheFactoryProvider, + $controller: $ControllerProvider, + $document: $DocumentProvider, + $exceptionHandler: $ExceptionHandlerProvider, + $filter: $FilterProvider, + $interpolate: $InterpolateProvider, + $interval: $IntervalProvider, + $http: $HttpProvider, + $httpBackend: $HttpBackendProvider, + $location: $LocationProvider, + $log: $LogProvider, + $parse: $ParseProvider, + $rootScope: $RootScopeProvider, + $q: $QProvider, + $sce: $SceProvider, + $sceDelegate: $SceDelegateProvider, + $sniffer: $SnifferProvider, + $templateCache: $TemplateCacheProvider, + $timeout: $TimeoutProvider, + $window: $WindowProvider + }); + } + ]); +} + +/* global + + -JQLitePrototype, + -addEventListenerFn, + -removeEventListenerFn, + -BOOLEAN_ATTR +*/ + +////////////////////////////////// +//JQLite +////////////////////////////////// + +/** + * @ngdoc function + * @name angular.element + * @function + * + * @description + * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element. + * + * If jQuery is available, `angular.element` is an alias for the + * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element` + * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite." + * + *
jqLite is a tiny, API-compatible subset of jQuery that allows + * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most + * commonly needed functionality with the goal of having a very small footprint.
+ * + * To use jQuery, simply load it before `DOMContentLoaded` event fired. + * + *
**Note:** all element references in Angular are always wrapped with jQuery or + * jqLite; they are never raw DOM references.
+ * + * ## Angular's jqLite + * jqLite provides only the following jQuery methods: + * + * - [`addClass()`](http://api.jquery.com/addClass/) + * - [`after()`](http://api.jquery.com/after/) + * - [`append()`](http://api.jquery.com/append/) + * - [`attr()`](http://api.jquery.com/attr/) + * - [`bind()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData + * - [`children()`](http://api.jquery.com/children/) - Does not support selectors + * - [`clone()`](http://api.jquery.com/clone/) + * - [`contents()`](http://api.jquery.com/contents/) + * - [`css()`](http://api.jquery.com/css/) + * - [`data()`](http://api.jquery.com/data/) + * - [`eq()`](http://api.jquery.com/eq/) + * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name + * - [`hasClass()`](http://api.jquery.com/hasClass/) + * - [`html()`](http://api.jquery.com/html/) + * - [`next()`](http://api.jquery.com/next/) - Does not support selectors + * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData + * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors + * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors + * - [`prepend()`](http://api.jquery.com/prepend/) + * - [`prop()`](http://api.jquery.com/prop/) + * - [`ready()`](http://api.jquery.com/ready/) + * - [`remove()`](http://api.jquery.com/remove/) + * - [`removeAttr()`](http://api.jquery.com/removeAttr/) + * - [`removeClass()`](http://api.jquery.com/removeClass/) + * - [`removeData()`](http://api.jquery.com/removeData/) + * - [`replaceWith()`](http://api.jquery.com/replaceWith/) + * - [`text()`](http://api.jquery.com/text/) + * - [`toggleClass()`](http://api.jquery.com/toggleClass/) + * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers. + * - [`unbind()`](http://api.jquery.com/off/) - Does not support namespaces + * - [`val()`](http://api.jquery.com/val/) + * - [`wrap()`](http://api.jquery.com/wrap/) + * + * ## jQuery/jqLite Extras + * Angular also provides the following additional methods and events to both jQuery and jqLite: + * + * ### Events + * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event + * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM + * element before it is removed. + * + * ### Methods + * - `controller(name)` - retrieves the controller of the current element or its parent. By default + * retrieves controller associated with the `ngController` directive. If `name` is provided as + * camelCase directive name, then the controller for this directive will be retrieved (e.g. + * `'ngModel'`). + * - `injector()` - retrieves the injector of the current element or its parent. + * - `scope()` - retrieves the {@link api/ng.$rootScope.Scope scope} of the current + * element or its parent. + * - `isolateScope()` - retrieves an isolate {@link api/ng.$rootScope.Scope scope} if one is attached directly to the + * current element. This getter should be used only on elements that contain a directive which starts a new isolate + * scope. Calling `scope()` on this element always returns the original non-isolate scope. + * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top + * parent element is reached. + * + * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery. + * @returns {Object} jQuery object. + */ + +var jqCache = JQLite.cache = {}, + jqName = JQLite.expando = 'ng-' + new Date().getTime(), + jqId = 1, + addEventListenerFn = (window.document.addEventListener + ? function(element, type, fn) {element.addEventListener(type, fn, false);} + : function(element, type, fn) {element.attachEvent('on' + type, fn);}), + removeEventListenerFn = (window.document.removeEventListener + ? function(element, type, fn) {element.removeEventListener(type, fn, false); } + : function(element, type, fn) {element.detachEvent('on' + type, fn); }); + +function jqNextId() { return ++jqId; } + + +var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g; +var MOZ_HACK_REGEXP = /^moz([A-Z])/; +var jqLiteMinErr = minErr('jqLite'); + +/** + * Converts snake_case to camelCase. + * Also there is special case for Moz prefix starting with upper case letter. + * @param name Name to normalize + */ +function camelCase(name) { + return name. + replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) { + return offset ? letter.toUpperCase() : letter; + }). + replace(MOZ_HACK_REGEXP, 'Moz$1'); +} + +///////////////////////////////////////////// +// jQuery mutation patch +// +// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a +// $destroy event on all DOM nodes being removed. +// +///////////////////////////////////////////// + +function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) { + var originalJqFn = jQuery.fn[name]; + originalJqFn = originalJqFn.$original || originalJqFn; + removePatch.$original = originalJqFn; + jQuery.fn[name] = removePatch; + + function removePatch(param) { + // jshint -W040 + var list = filterElems && param ? [this.filter(param)] : [this], + fireEvent = dispatchThis, + set, setIndex, setLength, + element, childIndex, childLength, children; + + if (!getterIfNoArguments || param != null) { + while(list.length) { + set = list.shift(); + for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) { + element = jqLite(set[setIndex]); + if (fireEvent) { + element.triggerHandler('$destroy'); + } else { + fireEvent = !fireEvent; + } + for(childIndex = 0, childLength = (children = element.children()).length; + childIndex < childLength; + childIndex++) { + list.push(jQuery(children[childIndex])); + } + } + } + } + return originalJqFn.apply(this, arguments); + } +} + +///////////////////////////////////////////// +function JQLite(element) { + if (element instanceof JQLite) { + return element; + } + if (!(this instanceof JQLite)) { + if (isString(element) && element.charAt(0) != '<') { + throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element'); + } + return new JQLite(element); + } + + if (isString(element)) { + var div = document.createElement('div'); + // Read about the NoScope elements here: + // http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx + div.innerHTML = '
 
' + element; // IE insanity to make NoScope elements work! + div.removeChild(div.firstChild); // remove the superfluous div + jqLiteAddNodes(this, div.childNodes); + var fragment = jqLite(document.createDocumentFragment()); + fragment.append(this); // detach the elements from the temporary DOM div. + } else { + jqLiteAddNodes(this, element); + } +} + +function jqLiteClone(element) { + return element.cloneNode(true); +} + +function jqLiteDealoc(element){ + jqLiteRemoveData(element); + for ( var i = 0, children = element.childNodes || []; i < children.length; i++) { + jqLiteDealoc(children[i]); + } +} + +function jqLiteOff(element, type, fn, unsupported) { + if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument'); + + var events = jqLiteExpandoStore(element, 'events'), + handle = jqLiteExpandoStore(element, 'handle'); + + if (!handle) return; //no listeners registered + + if (isUndefined(type)) { + forEach(events, function(eventHandler, type) { + removeEventListenerFn(element, type, eventHandler); + delete events[type]; + }); + } else { + forEach(type.split(' '), function(type) { + if (isUndefined(fn)) { + removeEventListenerFn(element, type, events[type]); + delete events[type]; + } else { + arrayRemove(events[type] || [], fn); + } + }); + } +} + +function jqLiteRemoveData(element, name) { + var expandoId = element[jqName], + expandoStore = jqCache[expandoId]; + + if (expandoStore) { + if (name) { + delete jqCache[expandoId].data[name]; + return; + } + + if (expandoStore.handle) { + expandoStore.events.$destroy && expandoStore.handle({}, '$destroy'); + jqLiteOff(element); + } + delete jqCache[expandoId]; + element[jqName] = undefined; // ie does not allow deletion of attributes on elements. + } +} + +function jqLiteExpandoStore(element, key, value) { + var expandoId = element[jqName], + expandoStore = jqCache[expandoId || -1]; + + if (isDefined(value)) { + if (!expandoStore) { + element[jqName] = expandoId = jqNextId(); + expandoStore = jqCache[expandoId] = {}; + } + expandoStore[key] = value; + } else { + return expandoStore && expandoStore[key]; + } +} + +function jqLiteData(element, key, value) { + var data = jqLiteExpandoStore(element, 'data'), + isSetter = isDefined(value), + keyDefined = !isSetter && isDefined(key), + isSimpleGetter = keyDefined && !isObject(key); + + if (!data && !isSimpleGetter) { + jqLiteExpandoStore(element, 'data', data = {}); + } + + if (isSetter) { + data[key] = value; + } else { + if (keyDefined) { + if (isSimpleGetter) { + // don't create data in this case. + return data && data[key]; + } else { + extend(data, key); + } + } else { + return data; + } + } +} + +function jqLiteHasClass(element, selector) { + if (!element.getAttribute) return false; + return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " "). + indexOf( " " + selector + " " ) > -1); +} + +function jqLiteRemoveClass(element, cssClasses) { + if (cssClasses && element.setAttribute) { + forEach(cssClasses.split(' '), function(cssClass) { + element.setAttribute('class', trim( + (" " + (element.getAttribute('class') || '') + " ") + .replace(/[\n\t]/g, " ") + .replace(" " + trim(cssClass) + " ", " ")) + ); + }); + } +} + +function jqLiteAddClass(element, cssClasses) { + if (cssClasses && element.setAttribute) { + var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ') + .replace(/[\n\t]/g, " "); + + forEach(cssClasses.split(' '), function(cssClass) { + cssClass = trim(cssClass); + if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) { + existingClasses += cssClass + ' '; + } + }); + + element.setAttribute('class', trim(existingClasses)); + } +} + +function jqLiteAddNodes(root, elements) { + if (elements) { + elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements)) + ? elements + : [ elements ]; + for(var i=0; i < elements.length; i++) { + root.push(elements[i]); + } + } +} + +function jqLiteController(element, name) { + return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller'); +} + +function jqLiteInheritedData(element, name, value) { + element = jqLite(element); + + // if element is the document object work with the html element instead + // this makes $(document).scope() possible + if(element[0].nodeType == 9) { + element = element.find('html'); + } + var names = isArray(name) ? name : [name]; + + while (element.length) { + + for (var i = 0, ii = names.length; i < ii; i++) { + if ((value = element.data(names[i])) !== undefined) return value; + } + element = element.parent(); + } +} + +////////////////////////////////////////// +// Functions which are declared directly. +////////////////////////////////////////// +var JQLitePrototype = JQLite.prototype = { + ready: function(fn) { + var fired = false; + + function trigger() { + if (fired) return; + fired = true; + fn(); + } + + // check if document already is loaded + if (document.readyState === 'complete'){ + setTimeout(trigger); + } else { + this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9 + // we can not use jqLite since we are not done loading and jQuery could be loaded later. + // jshint -W064 + JQLite(window).on('load', trigger); // fallback to window.onload for others + // jshint +W064 + } + }, + toString: function() { + var value = []; + forEach(this, function(e){ value.push('' + e);}); + return '[' + value.join(', ') + ']'; + }, + + eq: function(index) { + return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]); + }, + + length: 0, + push: push, + sort: [].sort, + splice: [].splice +}; + +////////////////////////////////////////// +// Functions iterating getter/setters. +// these functions return self on setter and +// value on get. +////////////////////////////////////////// +var BOOLEAN_ATTR = {}; +forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) { + BOOLEAN_ATTR[lowercase(value)] = value; +}); +var BOOLEAN_ELEMENTS = {}; +forEach('input,select,option,textarea,button,form,details'.split(','), function(value) { + BOOLEAN_ELEMENTS[uppercase(value)] = true; +}); + +function getBooleanAttrName(element, name) { + // check dom last since we will most likely fail on name + var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()]; + + // booleanAttr is here twice to minimize DOM access + return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr; +} + +forEach({ + data: jqLiteData, + inheritedData: jqLiteInheritedData, + + scope: function(element) { + // Can't use jqLiteData here directly so we stay compatible with jQuery! + return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']); + }, + + isolateScope: function(element) { + // Can't use jqLiteData here directly so we stay compatible with jQuery! + return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate'); + }, + + controller: jqLiteController , + + injector: function(element) { + return jqLiteInheritedData(element, '$injector'); + }, + + removeAttr: function(element,name) { + element.removeAttribute(name); + }, + + hasClass: jqLiteHasClass, + + css: function(element, name, value) { + name = camelCase(name); + + if (isDefined(value)) { + element.style[name] = value; + } else { + var val; + + if (msie <= 8) { + // this is some IE specific weirdness that jQuery 1.6.4 does not sure why + val = element.currentStyle && element.currentStyle[name]; + if (val === '') val = 'auto'; + } + + val = val || element.style[name]; + + if (msie <= 8) { + // jquery weirdness :-/ + val = (val === '') ? undefined : val; + } + + return val; + } + }, + + attr: function(element, name, value){ + var lowercasedName = lowercase(name); + if (BOOLEAN_ATTR[lowercasedName]) { + if (isDefined(value)) { + if (!!value) { + element[name] = true; + element.setAttribute(name, lowercasedName); + } else { + element[name] = false; + element.removeAttribute(lowercasedName); + } + } else { + return (element[name] || + (element.attributes.getNamedItem(name)|| noop).specified) + ? lowercasedName + : undefined; + } + } else if (isDefined(value)) { + element.setAttribute(name, value); + } else if (element.getAttribute) { + // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code + // some elements (e.g. Document) don't have get attribute, so return undefined + var ret = element.getAttribute(name, 2); + // normalize non-existing attributes to undefined (as jQuery) + return ret === null ? undefined : ret; + } + }, + + prop: function(element, name, value) { + if (isDefined(value)) { + element[name] = value; + } else { + return element[name]; + } + }, + + text: (function() { + var NODE_TYPE_TEXT_PROPERTY = []; + if (msie < 9) { + NODE_TYPE_TEXT_PROPERTY[1] = 'innerText'; /** Element **/ + NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue'; /** Text **/ + } else { + NODE_TYPE_TEXT_PROPERTY[1] = /** Element **/ + NODE_TYPE_TEXT_PROPERTY[3] = 'textContent'; /** Text **/ + } + getText.$dv = ''; + return getText; + + function getText(element, value) { + var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType]; + if (isUndefined(value)) { + return textProp ? element[textProp] : ''; + } + element[textProp] = value; + } + })(), + + val: function(element, value) { + if (isUndefined(value)) { + if (nodeName_(element) === 'SELECT' && element.multiple) { + var result = []; + forEach(element.options, function (option) { + if (option.selected) { + result.push(option.value || option.text); + } + }); + return result.length === 0 ? null : result; + } + return element.value; + } + element.value = value; + }, + + html: function(element, value) { + if (isUndefined(value)) { + return element.innerHTML; + } + for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) { + jqLiteDealoc(childNodes[i]); + } + element.innerHTML = value; + } +}, function(fn, name){ + /** + * Properties: writes return selection, reads return first value + */ + JQLite.prototype[name] = function(arg1, arg2) { + var i, key; + + // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it + // in a way that survives minification. + if (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined) { + if (isObject(arg1)) { + + // we are a write, but the object properties are the key/values + for(i=0; i < this.length; i++) { + if (fn === jqLiteData) { + // data() takes the whole object in jQuery + fn(this[i], arg1); + } else { + for (key in arg1) { + fn(this[i], key, arg1[key]); + } + } + } + // return self for chaining + return this; + } else { + // we are a read, so read the first child. + var value = fn.$dv; + // Only if we have $dv do we iterate over all, otherwise it is just the first element. + var jj = (value === undefined) ? Math.min(this.length, 1) : this.length; + for (var j = 0; j < jj; j++) { + var nodeValue = fn(this[j], arg1, arg2); + value = value ? value + nodeValue : nodeValue; + } + return value; + } + } else { + // we are a write, so apply to all children + for(i=0; i < this.length; i++) { + fn(this[i], arg1, arg2); + } + // return self for chaining + return this; + } + }; +}); + +function createEventHandler(element, events) { + var eventHandler = function (event, type) { + if (!event.preventDefault) { + event.preventDefault = function() { + event.returnValue = false; //ie + }; + } + + if (!event.stopPropagation) { + event.stopPropagation = function() { + event.cancelBubble = true; //ie + }; + } + + if (!event.target) { + event.target = event.srcElement || document; + } + + if (isUndefined(event.defaultPrevented)) { + var prevent = event.preventDefault; + event.preventDefault = function() { + event.defaultPrevented = true; + prevent.call(event); + }; + event.defaultPrevented = false; + } + + event.isDefaultPrevented = function() { + return event.defaultPrevented || event.returnValue === false; + }; + + forEach(events[type || event.type], function(fn) { + fn.call(element, event); + }); + + // Remove monkey-patched methods (IE), + // as they would cause memory leaks in IE8. + if (msie <= 8) { + // IE7/8 does not allow to delete property on native object + event.preventDefault = null; + event.stopPropagation = null; + event.isDefaultPrevented = null; + } else { + // It shouldn't affect normal browsers (native methods are defined on prototype). + delete event.preventDefault; + delete event.stopPropagation; + delete event.isDefaultPrevented; + } + }; + eventHandler.elem = element; + return eventHandler; +} + +////////////////////////////////////////// +// Functions iterating traversal. +// These functions chain results into a single +// selector. +////////////////////////////////////////// +forEach({ + removeData: jqLiteRemoveData, + + dealoc: jqLiteDealoc, + + on: function onFn(element, type, fn, unsupported){ + if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters'); + + var events = jqLiteExpandoStore(element, 'events'), + handle = jqLiteExpandoStore(element, 'handle'); + + if (!events) jqLiteExpandoStore(element, 'events', events = {}); + if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events)); + + forEach(type.split(' '), function(type){ + var eventFns = events[type]; + + if (!eventFns) { + if (type == 'mouseenter' || type == 'mouseleave') { + var contains = document.body.contains || document.body.compareDocumentPosition ? + function( a, b ) { + // jshint bitwise: false + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + events[type] = []; + + // Refer to jQuery's implementation of mouseenter & mouseleave + // Read about mouseenter and mouseleave: + // http://www.quirksmode.org/js/events_mouse.html#link8 + var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"}; + + onFn(element, eventmap[type], function(event) { + var target = this, related = event.relatedTarget; + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !contains(target, related)) ){ + handle(event, type); + } + }); + + } else { + addEventListenerFn(element, type, handle); + events[type] = []; + } + eventFns = events[type]; + } + eventFns.push(fn); + }); + }, + + off: jqLiteOff, + + replaceWith: function(element, replaceNode) { + var index, parent = element.parentNode; + jqLiteDealoc(element); + forEach(new JQLite(replaceNode), function(node){ + if (index) { + parent.insertBefore(node, index.nextSibling); + } else { + parent.replaceChild(node, element); + } + index = node; + }); + }, + + children: function(element) { + var children = []; + forEach(element.childNodes, function(element){ + if (element.nodeType === 1) + children.push(element); + }); + return children; + }, + + contents: function(element) { + return element.childNodes || []; + }, + + append: function(element, node) { + forEach(new JQLite(node), function(child){ + if (element.nodeType === 1 || element.nodeType === 11) { + element.appendChild(child); + } + }); + }, + + prepend: function(element, node) { + if (element.nodeType === 1) { + var index = element.firstChild; + forEach(new JQLite(node), function(child){ + element.insertBefore(child, index); + }); + } + }, + + wrap: function(element, wrapNode) { + wrapNode = jqLite(wrapNode)[0]; + var parent = element.parentNode; + if (parent) { + parent.replaceChild(wrapNode, element); + } + wrapNode.appendChild(element); + }, + + remove: function(element) { + jqLiteDealoc(element); + var parent = element.parentNode; + if (parent) parent.removeChild(element); + }, + + after: function(element, newElement) { + var index = element, parent = element.parentNode; + forEach(new JQLite(newElement), function(node){ + parent.insertBefore(node, index.nextSibling); + index = node; + }); + }, + + addClass: jqLiteAddClass, + removeClass: jqLiteRemoveClass, + + toggleClass: function(element, selector, condition) { + if (isUndefined(condition)) { + condition = !jqLiteHasClass(element, selector); + } + (condition ? jqLiteAddClass : jqLiteRemoveClass)(element, selector); + }, + + parent: function(element) { + var parent = element.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + + next: function(element) { + if (element.nextElementSibling) { + return element.nextElementSibling; + } + + // IE8 doesn't have nextElementSibling + var elm = element.nextSibling; + while (elm != null && elm.nodeType !== 1) { + elm = elm.nextSibling; + } + return elm; + }, + + find: function(element, selector) { + return element.getElementsByTagName(selector); + }, + + clone: jqLiteClone, + + triggerHandler: function(element, eventName, eventData) { + var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName]; + + eventData = eventData || []; + + var event = [{ + preventDefault: noop, + stopPropagation: noop + }]; + + forEach(eventFns, function(fn) { + fn.apply(element, event.concat(eventData)); + }); + } +}, function(fn, name){ + /** + * chaining functions + */ + JQLite.prototype[name] = function(arg1, arg2, arg3) { + var value; + for(var i=0; i < this.length; i++) { + if (isUndefined(value)) { + value = fn(this[i], arg1, arg2, arg3); + if (isDefined(value)) { + // any function which returns a value needs to be wrapped + value = jqLite(value); + } + } else { + jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3)); + } + } + return isDefined(value) ? value : this; + }; + + // bind legacy bind/unbind to on/off + JQLite.prototype.bind = JQLite.prototype.on; + JQLite.prototype.unbind = JQLite.prototype.off; +}); + +/** + * Computes a hash of an 'obj'. + * Hash of a: + * string is string + * number is number as string + * object is either result of calling $$hashKey function on the object or uniquely generated id, + * that is also assigned to the $$hashKey property of the object. + * + * @param obj + * @returns {string} hash string such that the same input will have the same hash string. + * The resulting string key is in 'type:hashKey' format. + */ +function hashKey(obj) { + var objType = typeof obj, + key; + + if (objType == 'object' && obj !== null) { + if (typeof (key = obj.$$hashKey) == 'function') { + // must invoke on object to keep the right this + key = obj.$$hashKey(); + } else if (key === undefined) { + key = obj.$$hashKey = nextUid(); + } + } else { + key = obj; + } + + return objType + ':' + key; +} + +/** + * HashMap which can use objects as keys + */ +function HashMap(array){ + forEach(array, this.put, this); +} +HashMap.prototype = { + /** + * Store key value pair + * @param key key to store can be any type + * @param value value to store can be any type + */ + put: function(key, value) { + this[hashKey(key)] = value; + }, + + /** + * @param key + * @returns the value for the key + */ + get: function(key) { + return this[hashKey(key)]; + }, + + /** + * Remove the key/value pair + * @param key + */ + remove: function(key) { + var value = this[key = hashKey(key)]; + delete this[key]; + return value; + } +}; + +/** + * @ngdoc function + * @name angular.injector + * @function + * + * @description + * Creates an injector function that can be used for retrieving services as well as for + * dependency injection (see {@link guide/di dependency injection}). + * + + * @param {Array.} modules A list of module functions or their aliases. See + * {@link angular.module}. The `ng` module must be explicitly added. + * @returns {function()} Injector function. See {@link AUTO.$injector $injector}. + * + * @example + * Typical usage + *
+ *   // create an injector
+ *   var $injector = angular.injector(['ng']);
+ *
+ *   // use the injector to kick off your application
+ *   // use the type inference to auto inject arguments, or use implicit injection
+ *   $injector.invoke(function($rootScope, $compile, $document){
+ *     $compile($document)($rootScope);
+ *     $rootScope.$digest();
+ *   });
+ * 
+ */ + + +/** + * @ngdoc overview + * @name AUTO + * @description + * + * Implicit module which gets automatically added to each {@link AUTO.$injector $injector}. + */ + +var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; +var FN_ARG_SPLIT = /,/; +var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; +var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; +var $injectorMinErr = minErr('$injector'); +function annotate(fn) { + var $inject, + fnText, + argDecl, + last; + + if (typeof fn == 'function') { + if (!($inject = fn.$inject)) { + $inject = []; + if (fn.length) { + fnText = fn.toString().replace(STRIP_COMMENTS, ''); + argDecl = fnText.match(FN_ARGS); + forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){ + arg.replace(FN_ARG, function(all, underscore, name){ + $inject.push(name); + }); + }); + } + fn.$inject = $inject; + } + } else if (isArray(fn)) { + last = fn.length - 1; + assertArgFn(fn[last], 'fn'); + $inject = fn.slice(0, last); + } else { + assertArgFn(fn, 'fn', true); + } + return $inject; +} + +/////////////////////////////////////// + +/** + * @ngdoc object + * @name AUTO.$injector + * @function + * + * @description + * + * `$injector` is used to retrieve object instances as defined by + * {@link AUTO.$provide provider}, instantiate types, invoke methods, + * and load modules. + * + * The following always holds true: + * + *
+ *   var $injector = angular.injector();
+ *   expect($injector.get('$injector')).toBe($injector);
+ *   expect($injector.invoke(function($injector){
+ *     return $injector;
+ *   }).toBe($injector);
+ * 
+ * + * # Injection Function Annotation + * + * JavaScript does not have annotations, and annotations are needed for dependency injection. The + * following are all valid ways of annotating function with injection arguments and are equivalent. + * + *
+ *   // inferred (only works if code not minified/obfuscated)
+ *   $injector.invoke(function(serviceA){});
+ *
+ *   // annotated
+ *   function explicit(serviceA) {};
+ *   explicit.$inject = ['serviceA'];
+ *   $injector.invoke(explicit);
+ *
+ *   // inline
+ *   $injector.invoke(['serviceA', function(serviceA){}]);
+ * 
+ * + * ## Inference + * + * In JavaScript calling `toString()` on a function returns the function definition. The definition + * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with + * minification, and obfuscation tools since these tools change the argument names. + * + * ## `$inject` Annotation + * By adding a `$inject` property onto a function the injection parameters can be specified. + * + * ## Inline + * As an array of injection names, where the last item in the array is the function to call. + */ + +/** + * @ngdoc method + * @name AUTO.$injector#get + * @methodOf AUTO.$injector + * + * @description + * Return an instance of the service. + * + * @param {string} name The name of the instance to retrieve. + * @return {*} The instance. + */ + +/** + * @ngdoc method + * @name AUTO.$injector#invoke + * @methodOf AUTO.$injector + * + * @description + * Invoke the method and supply the method arguments from the `$injector`. + * + * @param {!function} fn The function to invoke. Function parameters are injected according to the + * {@link guide/di $inject Annotation} rules. + * @param {Object=} self The `this` for the invoked method. + * @param {Object=} locals Optional object. If preset then any argument names are read from this + * object first, before the `$injector` is consulted. + * @returns {*} the value returned by the invoked `fn` function. + */ + +/** + * @ngdoc method + * @name AUTO.$injector#has + * @methodOf AUTO.$injector + * + * @description + * Allows the user to query if the particular service exist. + * + * @param {string} Name of the service to query. + * @returns {boolean} returns true if injector has given service. + */ + +/** + * @ngdoc method + * @name AUTO.$injector#instantiate + * @methodOf AUTO.$injector + * @description + * Create a new instance of JS type. The method takes a constructor function invokes the new + * operator and supplies all of the arguments to the constructor function as specified by the + * constructor annotation. + * + * @param {function} Type Annotated constructor function. + * @param {Object=} locals Optional object. If preset then any argument names are read from this + * object first, before the `$injector` is consulted. + * @returns {Object} new instance of `Type`. + */ + +/** + * @ngdoc method + * @name AUTO.$injector#annotate + * @methodOf AUTO.$injector + * + * @description + * Returns an array of service names which the function is requesting for injection. This API is + * used by the injector to determine which services need to be injected into the function when the + * function is invoked. There are three ways in which the function can be annotated with the needed + * dependencies. + * + * # Argument names + * + * The simplest form is to extract the dependencies from the arguments of the function. This is done + * by converting the function into a string using `toString()` method and extracting the argument + * names. + *
+ *   // Given
+ *   function MyController($scope, $route) {
+ *     // ...
+ *   }
+ *
+ *   // Then
+ *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
+ * 
+ * + * This method does not work with code minification / obfuscation. For this reason the following + * annotation strategies are supported. + * + * # The `$inject` property + * + * If a function has an `$inject` property and its value is an array of strings, then the strings + * represent names of services to be injected into the function. + *
+ *   // Given
+ *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
+ *     // ...
+ *   }
+ *   // Define function dependencies
+ *   MyController.$inject = ['$scope', '$route'];
+ *
+ *   // Then
+ *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
+ * 
+ * + * # The array notation + * + * It is often desirable to inline Injected functions and that's when setting the `$inject` property + * is very inconvenient. In these situations using the array notation to specify the dependencies in + * a way that survives minification is a better choice: + * + *
+ *   // We wish to write this (not minification / obfuscation safe)
+ *   injector.invoke(function($compile, $rootScope) {
+ *     // ...
+ *   });
+ *
+ *   // We are forced to write break inlining
+ *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
+ *     // ...
+ *   };
+ *   tmpFn.$inject = ['$compile', '$rootScope'];
+ *   injector.invoke(tmpFn);
+ *
+ *   // To better support inline function the inline annotation is supported
+ *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
+ *     // ...
+ *   }]);
+ *
+ *   // Therefore
+ *   expect(injector.annotate(
+ *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
+ *    ).toEqual(['$compile', '$rootScope']);
+ * 
+ * + * @param {function|Array.} fn Function for which dependent service names need to + * be retrieved as described above. + * + * @returns {Array.} The names of the services which the function requires. + */ + + + + +/** + * @ngdoc object + * @name AUTO.$provide + * + * @description + * + * The {@link AUTO.$provide $provide} service has a number of methods for registering components + * with the {@link AUTO.$injector $injector}. Many of these functions are also exposed on + * {@link angular.Module}. + * + * An Angular **service** is a singleton object created by a **service factory**. These **service + * factories** are functions which, in turn, are created by a **service provider**. + * The **service providers** are constructor functions. When instantiated they must contain a + * property called `$get`, which holds the **service factory** function. + * + * When you request a service, the {@link AUTO.$injector $injector} is responsible for finding the + * correct **service provider**, instantiating it and then calling its `$get` **service factory** + * function to get the instance of the **service**. + * + * Often services have no configuration options and there is no need to add methods to the service + * provider. The provider will be no more than a constructor function with a `$get` property. For + * these cases the {@link AUTO.$provide $provide} service has additional helper methods to register + * services without specifying a provider. + * + * * {@link AUTO.$provide#methods_provider provider(provider)} - registers a **service provider** with the + * {@link AUTO.$injector $injector} + * * {@link AUTO.$provide#methods_constant constant(obj)} - registers a value/object that can be accessed by + * providers and services. + * * {@link AUTO.$provide#methods_value value(obj)} - registers a value/object that can only be accessed by + * services, not providers. + * * {@link AUTO.$provide#methods_factory factory(fn)} - registers a service **factory function**, `fn`, + * that will be wrapped in a **service provider** object, whose `$get` property will contain the + * given factory function. + * * {@link AUTO.$provide#methods_service service(class)} - registers a **constructor function**, `class` that + * that will be wrapped in a **service provider** object, whose `$get` property will instantiate + * a new object using the given constructor function. + * + * See the individual methods for more information and examples. + */ + +/** + * @ngdoc method + * @name AUTO.$provide#provider + * @methodOf AUTO.$provide + * @description + * + * Register a **provider function** with the {@link AUTO.$injector $injector}. Provider functions + * are constructor functions, whose instances are responsible for "providing" a factory for a + * service. + * + * Service provider names start with the name of the service they provide followed by `Provider`. + * For example, the {@link ng.$log $log} service has a provider called + * {@link ng.$logProvider $logProvider}. + * + * Service provider objects can have additional methods which allow configuration of the provider + * and its service. Importantly, you can configure what kind of service is created by the `$get` + * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a + * method {@link ng.$logProvider#debugEnabled debugEnabled} + * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the + * console or not. + * + * @param {string} name The name of the instance. NOTE: the provider will be available under `name + + 'Provider'` key. + * @param {(Object|function())} provider If the provider is: + * + * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using + * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be + * created. + * - `Constructor`: a new instance of the provider will be created using + * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as + * `object`. + * + * @returns {Object} registered provider instance + + * @example + * + * The following example shows how to create a simple event tracking service and register it using + * {@link AUTO.$provide#methods_provider $provide.provider()}. + * + *
+ *  // Define the eventTracker provider
+ *  function EventTrackerProvider() {
+ *    var trackingUrl = '/track';
+ *
+ *    // A provider method for configuring where the tracked events should been saved
+ *    this.setTrackingUrl = function(url) {
+ *      trackingUrl = url;
+ *    };
+ *
+ *    // The service factory function
+ *    this.$get = ['$http', function($http) {
+ *      var trackedEvents = {};
+ *      return {
+ *        // Call this to track an event
+ *        event: function(event) {
+ *          var count = trackedEvents[event] || 0;
+ *          count += 1;
+ *          trackedEvents[event] = count;
+ *          return count;
+ *        },
+ *        // Call this to save the tracked events to the trackingUrl
+ *        save: function() {
+ *          $http.post(trackingUrl, trackedEvents);
+ *        }
+ *      };
+ *    }];
+ *  }
+ *
+ *  describe('eventTracker', function() {
+ *    var postSpy;
+ *
+ *    beforeEach(module(function($provide) {
+ *      // Register the eventTracker provider
+ *      $provide.provider('eventTracker', EventTrackerProvider);
+ *    }));
+ *
+ *    beforeEach(module(function(eventTrackerProvider) {
+ *      // Configure eventTracker provider
+ *      eventTrackerProvider.setTrackingUrl('/custom-track');
+ *    }));
+ *
+ *    it('tracks events', inject(function(eventTracker) {
+ *      expect(eventTracker.event('login')).toEqual(1);
+ *      expect(eventTracker.event('login')).toEqual(2);
+ *    }));
+ *
+ *    it('saves to the tracking url', inject(function(eventTracker, $http) {
+ *      postSpy = spyOn($http, 'post');
+ *      eventTracker.event('login');
+ *      eventTracker.save();
+ *      expect(postSpy).toHaveBeenCalled();
+ *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
+ *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
+ *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
+ *    }));
+ *  });
+ * 
+ */ + +/** + * @ngdoc method + * @name AUTO.$provide#factory + * @methodOf AUTO.$provide + * @description + * + * Register a **service factory**, which will be called to return the service instance. + * This is short for registering a service where its provider consists of only a `$get` property, + * which is the given service factory function. + * You should use {@link AUTO.$provide#factory $provide.factory(getFn)} if you do not need to + * configure your service in a provider. + * + * @param {string} name The name of the instance. + * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand + * for `$provide.provider(name, {$get: $getFn})`. + * @returns {Object} registered provider instance + * + * @example + * Here is an example of registering a service + *
+ *   $provide.factory('ping', ['$http', function($http) {
+ *     return function ping() {
+ *       return $http.send('/ping');
+ *     };
+ *   }]);
+ * 
+ * You would then inject and use this service like this: + *
+ *   someModule.controller('Ctrl', ['ping', function(ping) {
+ *     ping();
+ *   }]);
+ * 
+ */ + + +/** + * @ngdoc method + * @name AUTO.$provide#service + * @methodOf AUTO.$provide + * @description + * + * Register a **service constructor**, which will be invoked with `new` to create the service + * instance. + * This is short for registering a service where its provider's `$get` property is the service + * constructor function that will be used to instantiate the service instance. + * + * You should use {@link AUTO.$provide#methods_service $provide.service(class)} if you define your service + * as a type/class. This is common when using {@link http://coffeescript.org CoffeeScript}. + * + * @param {string} name The name of the instance. + * @param {Function} constructor A class (constructor function) that will be instantiated. + * @returns {Object} registered provider instance + * + * @example + * Here is an example of registering a service using + * {@link AUTO.$provide#methods_service $provide.service(class)} that is defined as a CoffeeScript class. + *
+ *   class Ping
+ *     constructor: (@$http)->
+ *     send: ()=>
+ *       @$http.get('/ping')
+ *
+ *   $provide.service('ping', ['$http', Ping])
+ * 
+ * You would then inject and use this service like this: + *
+ *   someModule.controller 'Ctrl', ['ping', (ping)->
+ *     ping.send()
+ *   ]
+ * 
+ */ + + +/** + * @ngdoc method + * @name AUTO.$provide#value + * @methodOf AUTO.$provide + * @description + * + * Register a **value service** with the {@link AUTO.$injector $injector}, such as a string, a + * number, an array, an object or a function. This is short for registering a service where its + * provider's `$get` property is a factory function that takes no arguments and returns the **value + * service**. + * + * Value services are similar to constant services, except that they cannot be injected into a + * module configuration function (see {@link angular.Module#config}) but they can be overridden by + * an Angular + * {@link AUTO.$provide#decorator decorator}. + * + * @param {string} name The name of the instance. + * @param {*} value The value. + * @returns {Object} registered provider instance + * + * @example + * Here are some examples of creating value services. + *
+ *   $provide.value('ADMIN_USER', 'admin');
+ *
+ *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
+ *
+ *   $provide.value('halfOf', function(value) {
+ *     return value / 2;
+ *   });
+ * 
+ */ + + +/** + * @ngdoc method + * @name AUTO.$provide#constant + * @methodOf AUTO.$provide + * @description + * + * Register a **constant service**, such as a string, a number, an array, an object or a function, + * with the {@link AUTO.$injector $injector}. Unlike {@link AUTO.$provide#value value} it can be + * injected into a module configuration function (see {@link angular.Module#config}) and it cannot + * be overridden by an Angular {@link AUTO.$provide#decorator decorator}. + * + * @param {string} name The name of the constant. + * @param {*} value The constant value. + * @returns {Object} registered instance + * + * @example + * Here a some examples of creating constants: + *
+ *   $provide.constant('SHARD_HEIGHT', 306);
+ *
+ *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
+ *
+ *   $provide.constant('double', function(value) {
+ *     return value * 2;
+ *   });
+ * 
+ */ + + +/** + * @ngdoc method + * @name AUTO.$provide#decorator + * @methodOf AUTO.$provide + * @description + * + * Register a **service decorator** with the {@link AUTO.$injector $injector}. A service decorator + * intercepts the creation of a service, allowing it to override or modify the behaviour of the + * service. The object returned by the decorator may be the original service, or a new service + * object which replaces or wraps and delegates to the original service. + * + * @param {string} name The name of the service to decorate. + * @param {function()} decorator This function will be invoked when the service needs to be + * instantiated and should return the decorated service instance. The function is called using + * the {@link AUTO.$injector#invoke injector.invoke} method and is therefore fully injectable. + * Local injection arguments: + * + * * `$delegate` - The original service instance, which can be monkey patched, configured, + * decorated or delegated to. + * + * @example + * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting + * calls to {@link ng.$log#error $log.warn()}. + *
+ *   $provider.decorator('$log', ['$delegate', function($delegate) {
+ *     $delegate.warn = $delegate.error;
+ *     return $delegate;
+ *   }]);
+ * 
+ */ + + +function createInjector(modulesToLoad) { + var INSTANTIATING = {}, + providerSuffix = 'Provider', + path = [], + loadedModules = new HashMap(), + providerCache = { + $provide: { + provider: supportObject(provider), + factory: supportObject(factory), + service: supportObject(service), + value: supportObject(value), + constant: supportObject(constant), + decorator: decorator + } + }, + providerInjector = (providerCache.$injector = + createInternalInjector(providerCache, function() { + throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- ')); + })), + instanceCache = {}, + instanceInjector = (instanceCache.$injector = + createInternalInjector(instanceCache, function(servicename) { + var provider = providerInjector.get(servicename + providerSuffix); + return instanceInjector.invoke(provider.$get, provider); + })); + + + forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); }); + + return instanceInjector; + + //////////////////////////////////// + // $provider + //////////////////////////////////// + + function supportObject(delegate) { + return function(key, value) { + if (isObject(key)) { + forEach(key, reverseParams(delegate)); + } else { + return delegate(key, value); + } + }; + } + + function provider(name, provider_) { + assertNotHasOwnProperty(name, 'service'); + if (isFunction(provider_) || isArray(provider_)) { + provider_ = providerInjector.instantiate(provider_); + } + if (!provider_.$get) { + throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name); + } + return providerCache[name + providerSuffix] = provider_; + } + + function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); } + + function service(name, constructor) { + return factory(name, ['$injector', function($injector) { + return $injector.instantiate(constructor); + }]); + } + + function value(name, val) { return factory(name, valueFn(val)); } + + function constant(name, value) { + assertNotHasOwnProperty(name, 'constant'); + providerCache[name] = value; + instanceCache[name] = value; + } + + function decorator(serviceName, decorFn) { + var origProvider = providerInjector.get(serviceName + providerSuffix), + orig$get = origProvider.$get; + + origProvider.$get = function() { + var origInstance = instanceInjector.invoke(orig$get, origProvider); + return instanceInjector.invoke(decorFn, null, {$delegate: origInstance}); + }; + } + + //////////////////////////////////// + // Module Loading + //////////////////////////////////// + function loadModules(modulesToLoad){ + var runBlocks = [], moduleFn, invokeQueue, i, ii; + forEach(modulesToLoad, function(module) { + if (loadedModules.get(module)) return; + loadedModules.put(module, true); + + try { + if (isString(module)) { + moduleFn = angularModule(module); + runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks); + + for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) { + var invokeArgs = invokeQueue[i], + provider = providerInjector.get(invokeArgs[0]); + + provider[invokeArgs[1]].apply(provider, invokeArgs[2]); + } + } else if (isFunction(module)) { + runBlocks.push(providerInjector.invoke(module)); + } else if (isArray(module)) { + runBlocks.push(providerInjector.invoke(module)); + } else { + assertArgFn(module, 'module'); + } + } catch (e) { + if (isArray(module)) { + module = module[module.length - 1]; + } + if (e.message && e.stack && e.stack.indexOf(e.message) == -1) { + // Safari & FF's stack traces don't contain error.message content + // unlike those of Chrome and IE + // So if stack doesn't contain message, we create a new string that contains both. + // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here. + /* jshint -W022 */ + e = e.message + '\n' + e.stack; + } + throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}", + module, e.stack || e.message || e); + } + }); + return runBlocks; + } + + //////////////////////////////////// + // internal Injector + //////////////////////////////////// + + function createInternalInjector(cache, factory) { + + function getService(serviceName) { + if (cache.hasOwnProperty(serviceName)) { + if (cache[serviceName] === INSTANTIATING) { + throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- ')); + } + return cache[serviceName]; + } else { + try { + path.unshift(serviceName); + cache[serviceName] = INSTANTIATING; + return cache[serviceName] = factory(serviceName); + } finally { + path.shift(); + } + } + } + + function invoke(fn, self, locals){ + var args = [], + $inject = annotate(fn), + length, i, + key; + + for(i = 0, length = $inject.length; i < length; i++) { + key = $inject[i]; + if (typeof key !== 'string') { + throw $injectorMinErr('itkn', + 'Incorrect injection token! Expected service name as string, got {0}', key); + } + args.push( + locals && locals.hasOwnProperty(key) + ? locals[key] + : getService(key) + ); + } + if (!fn.$inject) { + // this means that we must be an array. + fn = fn[length]; + } + + + // Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke + switch (self ? -1 : args.length) { + case 0: return fn(); + case 1: return fn(args[0]); + case 2: return fn(args[0], args[1]); + case 3: return fn(args[0], args[1], args[2]); + case 4: return fn(args[0], args[1], args[2], args[3]); + case 5: return fn(args[0], args[1], args[2], args[3], args[4]); + case 6: return fn(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + case 8: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); + case 9: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], + args[8]); + case 10: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], + args[8], args[9]); + default: return fn.apply(self, args); + } + } + + function instantiate(Type, locals) { + var Constructor = function() {}, + instance, returnedValue; + + // Check if Type is annotated and use just the given function at n-1 as parameter + // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); + Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype; + instance = new Constructor(); + returnedValue = invoke(Type, instance, locals); + + return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance; + } + + return { + invoke: invoke, + instantiate: instantiate, + get: getService, + annotate: annotate, + has: function(name) { + return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); + } + }; + } +} + +/** + * @ngdoc function + * @name ng.$anchorScroll + * @requires $window + * @requires $location + * @requires $rootScope + * + * @description + * When called, it checks current value of `$location.hash()` and scroll to related element, + * according to rules specified in + * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}. + * + * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor. + * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`. + * + * @example + + +
+ Go to bottom + You're at the bottom! +
+
+ + function ScrollCtrl($scope, $location, $anchorScroll) { + $scope.gotoBottom = function (){ + // set the location.hash to the id of + // the element you wish to scroll to. + $location.hash('bottom'); + + // call $anchorScroll() + $anchorScroll(); + } + } + + + #scrollArea { + height: 350px; + overflow: auto; + } + + #bottom { + display: block; + margin-top: 2000px; + } + +
+ */ +function $AnchorScrollProvider() { + + var autoScrollingEnabled = true; + + this.disableAutoScrolling = function() { + autoScrollingEnabled = false; + }; + + this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) { + var document = $window.document; + + // helper function to get first anchor from a NodeList + // can't use filter.filter, as it accepts only instances of Array + // and IE can't convert NodeList to an array using [].slice + // TODO(vojta): use filter if we change it to accept lists as well + function getFirstAnchor(list) { + var result = null; + forEach(list, function(element) { + if (!result && lowercase(element.nodeName) === 'a') result = element; + }); + return result; + } + + function scroll() { + var hash = $location.hash(), elm; + + // empty hash, scroll to the top of the page + if (!hash) $window.scrollTo(0, 0); + + // element with given id + else if ((elm = document.getElementById(hash))) elm.scrollIntoView(); + + // first anchor with given name :-D + else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView(); + + // no element and hash == 'top', scroll to the top of the page + else if (hash === 'top') $window.scrollTo(0, 0); + } + + // does not scroll when user clicks on anchor link that is currently on + // (no url change, no $location.hash() change), browser native does scroll + if (autoScrollingEnabled) { + $rootScope.$watch(function autoScrollWatch() {return $location.hash();}, + function autoScrollWatchAction() { + $rootScope.$evalAsync(scroll); + }); + } + + return scroll; + }]; +} + +var $animateMinErr = minErr('$animate'); + +/** + * @ngdoc object + * @name ng.$animateProvider + * + * @description + * Default implementation of $animate that doesn't perform any animations, instead just + * synchronously performs DOM + * updates and calls done() callbacks. + * + * In order to enable animations the ngAnimate module has to be loaded. + * + * To see the functional implementation check out src/ngAnimate/animate.js + */ +var $AnimateProvider = ['$provide', function($provide) { + + + this.$$selectors = {}; + + + /** + * @ngdoc function + * @name ng.$animateProvider#register + * @methodOf ng.$animateProvider + * + * @description + * Registers a new injectable animation factory function. The factory function produces the + * animation object which contains callback functions for each event that is expected to be + * animated. + * + * * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction` + * must be called once the element animation is complete. If a function is returned then the + * animation service will use this function to cancel the animation whenever a cancel event is + * triggered. + * + * + *
+   *   return {
+     *     eventFn : function(element, done) {
+     *       //code to run the animation
+     *       //once complete, then run done()
+     *       return function cancellationFunction() {
+     *         //code to cancel the animation
+     *       }
+     *     }
+     *   }
+   *
+ * + * @param {string} name The name of the animation. + * @param {function} factory The factory function that will be executed to return the animation + * object. + */ + this.register = function(name, factory) { + var key = name + '-animation'; + if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel', + "Expecting class selector starting with '.' got '{0}'.", name); + this.$$selectors[name.substr(1)] = key; + $provide.factory(key, factory); + }; + + this.$get = ['$timeout', function($timeout) { + + /** + * + * @ngdoc object + * @name ng.$animate + * @description The $animate service provides rudimentary DOM manipulation functions to + * insert, remove and move elements within the DOM, as well as adding and removing classes. + * This service is the core service used by the ngAnimate $animator service which provides + * high-level animation hooks for CSS and JavaScript. + * + * $animate is available in the AngularJS core, however, the ngAnimate module must be included + * to enable full out animation support. Otherwise, $animate will only perform simple DOM + * manipulation operations. + * + * To learn more about enabling animation support, click here to visit the {@link ngAnimate + * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service + * page}. + */ + return { + + /** + * + * @ngdoc function + * @name ng.$animate#enter + * @methodOf ng.$animate + * @function + * @description Inserts the element into the DOM either after the `after` element or within + * the `parent` element. Once complete, the done() callback will be fired (if provided). + * @param {jQuery/jqLite element} element the element which will be inserted into the DOM + * @param {jQuery/jqLite element} parent the parent element which will append the element as + * a child (if the after element is not present) + * @param {jQuery/jqLite element} after the sibling element which will append the element + * after itself + * @param {function=} done callback function that will be called after the element has been + * inserted into the DOM + */ + enter : function(element, parent, after, done) { + if (after) { + after.after(element); + } else { + if (!parent || !parent[0]) { + parent = after.parent(); + } + parent.append(element); + } + done && $timeout(done, 0, false); + }, + + /** + * + * @ngdoc function + * @name ng.$animate#leave + * @methodOf ng.$animate + * @function + * @description Removes the element from the DOM. Once complete, the done() callback will be + * fired (if provided). + * @param {jQuery/jqLite element} element the element which will be removed from the DOM + * @param {function=} done callback function that will be called after the element has been + * removed from the DOM + */ + leave : function(element, done) { + element.remove(); + done && $timeout(done, 0, false); + }, + + /** + * + * @ngdoc function + * @name ng.$animate#move + * @methodOf ng.$animate + * @function + * @description Moves the position of the provided element within the DOM to be placed + * either after the `after` element or inside of the `parent` element. Once complete, the + * done() callback will be fired (if provided). + * + * @param {jQuery/jqLite element} element the element which will be moved around within the + * DOM + * @param {jQuery/jqLite element} parent the parent element where the element will be + * inserted into (if the after element is not present) + * @param {jQuery/jqLite element} after the sibling element where the element will be + * positioned next to + * @param {function=} done the callback function (if provided) that will be fired after the + * element has been moved to its new position + */ + move : function(element, parent, after, done) { + // Do not remove element before insert. Removing will cause data associated with the + // element to be dropped. Insert will implicitly do the remove. + this.enter(element, parent, after, done); + }, + + /** + * + * @ngdoc function + * @name ng.$animate#addClass + * @methodOf ng.$animate + * @function + * @description Adds the provided className CSS class value to the provided element. Once + * complete, the done() callback will be fired (if provided). + * @param {jQuery/jqLite element} element the element which will have the className value + * added to it + * @param {string} className the CSS class which will be added to the element + * @param {function=} done the callback function (if provided) that will be fired after the + * className value has been added to the element + */ + addClass : function(element, className, done) { + className = isString(className) ? + className : + isArray(className) ? className.join(' ') : ''; + forEach(element, function (element) { + jqLiteAddClass(element, className); + }); + done && $timeout(done, 0, false); + }, + + /** + * + * @ngdoc function + * @name ng.$animate#removeClass + * @methodOf ng.$animate + * @function + * @description Removes the provided className CSS class value from the provided element. + * Once complete, the done() callback will be fired (if provided). + * @param {jQuery/jqLite element} element the element which will have the className value + * removed from it + * @param {string} className the CSS class which will be removed from the element + * @param {function=} done the callback function (if provided) that will be fired after the + * className value has been removed from the element + */ + removeClass : function(element, className, done) { + className = isString(className) ? + className : + isArray(className) ? className.join(' ') : ''; + forEach(element, function (element) { + jqLiteRemoveClass(element, className); + }); + done && $timeout(done, 0, false); + }, + + enabled : noop + }; + }]; +}]; + +/** + * ! This is a private undocumented service ! + * + * @name ng.$browser + * @requires $log + * @description + * This object has two goals: + * + * - hide all the global state in the browser caused by the window object + * - abstract away all the browser specific features and inconsistencies + * + * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser` + * service, which can be used for convenient testing of the application without the interaction with + * the real browser apis. + */ +/** + * @param {object} window The global window object. + * @param {object} document jQuery wrapped document. + * @param {function()} XHR XMLHttpRequest constructor. + * @param {object} $log console.log or an object with the same interface. + * @param {object} $sniffer $sniffer service + */ +function Browser(window, document, $log, $sniffer) { + var self = this, + rawDocument = document[0], + location = window.location, + history = window.history, + setTimeout = window.setTimeout, + clearTimeout = window.clearTimeout, + pendingDeferIds = {}; + + self.isMock = false; + + var outstandingRequestCount = 0; + var outstandingRequestCallbacks = []; + + // TODO(vojta): remove this temporary api + self.$$completeOutstandingRequest = completeOutstandingRequest; + self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; }; + + /** + * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks` + * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed. + */ + function completeOutstandingRequest(fn) { + try { + fn.apply(null, sliceArgs(arguments, 1)); + } finally { + outstandingRequestCount--; + if (outstandingRequestCount === 0) { + while(outstandingRequestCallbacks.length) { + try { + outstandingRequestCallbacks.pop()(); + } catch (e) { + $log.error(e); + } + } + } + } + } + + /** + * @private + * Note: this method is used only by scenario runner + * TODO(vojta): prefix this method with $$ ? + * @param {function()} callback Function that will be called when no outstanding request + */ + self.notifyWhenNoOutstandingRequests = function(callback) { + // force browser to execute all pollFns - this is needed so that cookies and other pollers fire + // at some deterministic time in respect to the test runner's actions. Leaving things up to the + // regular poller would result in flaky tests. + forEach(pollFns, function(pollFn){ pollFn(); }); + + if (outstandingRequestCount === 0) { + callback(); + } else { + outstandingRequestCallbacks.push(callback); + } + }; + + ////////////////////////////////////////////////////////////// + // Poll Watcher API + ////////////////////////////////////////////////////////////// + var pollFns = [], + pollTimeout; + + /** + * @name ng.$browser#addPollFn + * @methodOf ng.$browser + * + * @param {function()} fn Poll function to add + * + * @description + * Adds a function to the list of functions that poller periodically executes, + * and starts polling if not started yet. + * + * @returns {function()} the added function + */ + self.addPollFn = function(fn) { + if (isUndefined(pollTimeout)) startPoller(100, setTimeout); + pollFns.push(fn); + return fn; + }; + + /** + * @param {number} interval How often should browser call poll functions (ms) + * @param {function()} setTimeout Reference to a real or fake `setTimeout` function. + * + * @description + * Configures the poller to run in the specified intervals, using the specified + * setTimeout fn and kicks it off. + */ + function startPoller(interval, setTimeout) { + (function check() { + forEach(pollFns, function(pollFn){ pollFn(); }); + pollTimeout = setTimeout(check, interval); + })(); + } + + ////////////////////////////////////////////////////////////// + // URL API + ////////////////////////////////////////////////////////////// + + var lastBrowserUrl = location.href, + baseElement = document.find('base'), + newLocation = null; + + /** + * @name ng.$browser#url + * @methodOf ng.$browser + * + * @description + * GETTER: + * Without any argument, this method just returns current value of location.href. + * + * SETTER: + * With at least one argument, this method sets url to new value. + * If html5 history api supported, pushState/replaceState is used, otherwise + * location.href/location.replace is used. + * Returns its own instance to allow chaining + * + * NOTE: this api is intended for use only by the $location service. Please use the + * {@link ng.$location $location service} to change url. + * + * @param {string} url New url (when used as setter) + * @param {boolean=} replace Should new url replace current history record ? + */ + self.url = function(url, replace) { + // Android Browser BFCache causes location reference to become stale. + if (location !== window.location) location = window.location; + + // setter + if (url) { + if (lastBrowserUrl == url) return; + lastBrowserUrl = url; + if ($sniffer.history) { + if (replace) history.replaceState(null, '', url); + else { + history.pushState(null, '', url); + // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462 + baseElement.attr('href', baseElement.attr('href')); + } + } else { + newLocation = url; + if (replace) { + location.replace(url); + } else { + location.href = url; + } + } + return self; + // getter + } else { + // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href + // methods not updating location.href synchronously. + // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172 + return newLocation || location.href.replace(/%27/g,"'"); + } + }; + + var urlChangeListeners = [], + urlChangeInit = false; + + function fireUrlChange() { + newLocation = null; + if (lastBrowserUrl == self.url()) return; + + lastBrowserUrl = self.url(); + forEach(urlChangeListeners, function(listener) { + listener(self.url()); + }); + } + + /** + * @name ng.$browser#onUrlChange + * @methodOf ng.$browser + * @TODO(vojta): refactor to use node's syntax for events + * + * @description + * Register callback function that will be called, when url changes. + * + * It's only called when the url is changed by outside of angular: + * - user types different url into address bar + * - user clicks on history (forward/back) button + * - user clicks on a link + * + * It's not called when url is changed by $browser.url() method + * + * The listener gets called with new url as parameter. + * + * NOTE: this api is intended for use only by the $location service. Please use the + * {@link ng.$location $location service} to monitor url changes in angular apps. + * + * @param {function(string)} listener Listener function to be called when url changes. + * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous. + */ + self.onUrlChange = function(callback) { + if (!urlChangeInit) { + // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera) + // don't fire popstate when user change the address bar and don't fire hashchange when url + // changed by push/replaceState + + // html5 history api - popstate event + if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange); + // hashchange event + if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange); + // polling + else self.addPollFn(fireUrlChange); + + urlChangeInit = true; + } + + urlChangeListeners.push(callback); + return callback; + }; + + ////////////////////////////////////////////////////////////// + // Misc API + ////////////////////////////////////////////////////////////// + + /** + * @name ng.$browser#baseHref + * @methodOf ng.$browser + * + * @description + * Returns current + * (always relative - without domain) + * + * @returns {string=} current + */ + self.baseHref = function() { + var href = baseElement.attr('href'); + return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : ''; + }; + + ////////////////////////////////////////////////////////////// + // Cookies API + ////////////////////////////////////////////////////////////// + var lastCookies = {}; + var lastCookieString = ''; + var cookiePath = self.baseHref(); + + /** + * @name ng.$browser#cookies + * @methodOf ng.$browser + * + * @param {string=} name Cookie name + * @param {string=} value Cookie value + * + * @description + * The cookies method provides a 'private' low level access to browser cookies. + * It is not meant to be used directly, use the $cookie service instead. + * + * The return values vary depending on the arguments that the method was called with as follows: + * + * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify + * it + * - cookies(name, value) -> set name to value, if value is undefined delete the cookie + * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that + * way) + * + * @returns {Object} Hash of all cookies (if called without any parameter) + */ + self.cookies = function(name, value) { + /* global escape: false, unescape: false */ + var cookieLength, cookieArray, cookie, i, index; + + if (name) { + if (value === undefined) { + rawDocument.cookie = escape(name) + "=;path=" + cookiePath + + ";expires=Thu, 01 Jan 1970 00:00:00 GMT"; + } else { + if (isString(value)) { + cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + + ';path=' + cookiePath).length + 1; + + // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum: + // - 300 cookies + // - 20 cookies per unique domain + // - 4096 bytes per cookie + if (cookieLength > 4096) { + $log.warn("Cookie '"+ name + + "' possibly not set or overflowed because it was too large ("+ + cookieLength + " > 4096 bytes)!"); + } + } + } + } else { + if (rawDocument.cookie !== lastCookieString) { + lastCookieString = rawDocument.cookie; + cookieArray = lastCookieString.split("; "); + lastCookies = {}; + + for (i = 0; i < cookieArray.length; i++) { + cookie = cookieArray[i]; + index = cookie.indexOf('='); + if (index > 0) { //ignore nameless cookies + name = unescape(cookie.substring(0, index)); + // the first value that is seen for a cookie is the most + // specific one. values for the same cookie name that + // follow are for less specific paths. + if (lastCookies[name] === undefined) { + lastCookies[name] = unescape(cookie.substring(index + 1)); + } + } + } + } + return lastCookies; + } + }; + + + /** + * @name ng.$browser#defer + * @methodOf ng.$browser + * @param {function()} fn A function, who's execution should be deferred. + * @param {number=} [delay=0] of milliseconds to defer the function execution. + * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`. + * + * @description + * Executes a fn asynchronously via `setTimeout(fn, delay)`. + * + * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using + * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed + * via `$browser.defer.flush()`. + * + */ + self.defer = function(fn, delay) { + var timeoutId; + outstandingRequestCount++; + timeoutId = setTimeout(function() { + delete pendingDeferIds[timeoutId]; + completeOutstandingRequest(fn); + }, delay || 0); + pendingDeferIds[timeoutId] = true; + return timeoutId; + }; + + + /** + * @name ng.$browser#defer.cancel + * @methodOf ng.$browser.defer + * + * @description + * Cancels a deferred task identified with `deferId`. + * + * @param {*} deferId Token returned by the `$browser.defer` function. + * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully + * canceled. + */ + self.defer.cancel = function(deferId) { + if (pendingDeferIds[deferId]) { + delete pendingDeferIds[deferId]; + clearTimeout(deferId); + completeOutstandingRequest(noop); + return true; + } + return false; + }; + +} + +function $BrowserProvider(){ + this.$get = ['$window', '$log', '$sniffer', '$document', + function( $window, $log, $sniffer, $document){ + return new Browser($window, $document, $log, $sniffer); + }]; +} + +/** + * @ngdoc object + * @name ng.$cacheFactory + * + * @description + * Factory that constructs cache objects and gives access to them. + * + *
+ *
+ *  var cache = $cacheFactory('cacheId');
+ *  expect($cacheFactory.get('cacheId')).toBe(cache);
+ *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
+ *
+ *  cache.put("key", "value");
+ *  cache.put("another key", "another value");
+ *
+ *  // We've specified no options on creation
+ *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
+ *
+ * 
+ * + * + * @param {string} cacheId Name or id of the newly created cache. + * @param {object=} options Options object that specifies the cache behavior. Properties: + * + * - `{number=}` `capacity` — turns the cache into LRU cache. + * + * @returns {object} Newly created cache object with the following set of methods: + * + * - `{object}` `info()` — Returns id, size, and options of cache. + * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns + * it. + * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss. + * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache. + * - `{void}` `removeAll()` — Removes all cached values. + * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory. + * + */ +function $CacheFactoryProvider() { + + this.$get = function() { + var caches = {}; + + function cacheFactory(cacheId, options) { + if (cacheId in caches) { + throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId); + } + + var size = 0, + stats = extend({}, options, {id: cacheId}), + data = {}, + capacity = (options && options.capacity) || Number.MAX_VALUE, + lruHash = {}, + freshEnd = null, + staleEnd = null; + + return caches[cacheId] = { + + put: function(key, value) { + var lruEntry = lruHash[key] || (lruHash[key] = {key: key}); + + refresh(lruEntry); + + if (isUndefined(value)) return; + if (!(key in data)) size++; + data[key] = value; + + if (size > capacity) { + this.remove(staleEnd.key); + } + + return value; + }, + + + get: function(key) { + var lruEntry = lruHash[key]; + + if (!lruEntry) return; + + refresh(lruEntry); + + return data[key]; + }, + + + remove: function(key) { + var lruEntry = lruHash[key]; + + if (!lruEntry) return; + + if (lruEntry == freshEnd) freshEnd = lruEntry.p; + if (lruEntry == staleEnd) staleEnd = lruEntry.n; + link(lruEntry.n,lruEntry.p); + + delete lruHash[key]; + delete data[key]; + size--; + }, + + + removeAll: function() { + data = {}; + size = 0; + lruHash = {}; + freshEnd = staleEnd = null; + }, + + + destroy: function() { + data = null; + stats = null; + lruHash = null; + delete caches[cacheId]; + }, + + + info: function() { + return extend({}, stats, {size: size}); + } + }; + + + /** + * makes the `entry` the freshEnd of the LRU linked list + */ + function refresh(entry) { + if (entry != freshEnd) { + if (!staleEnd) { + staleEnd = entry; + } else if (staleEnd == entry) { + staleEnd = entry.n; + } + + link(entry.n, entry.p); + link(entry, freshEnd); + freshEnd = entry; + freshEnd.n = null; + } + } + + + /** + * bidirectionally links two entries of the LRU linked list + */ + function link(nextEntry, prevEntry) { + if (nextEntry != prevEntry) { + if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify + if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify + } + } + } + + + /** + * @ngdoc method + * @name ng.$cacheFactory#info + * @methodOf ng.$cacheFactory + * + * @description + * Get information about all the of the caches that have been created + * + * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info` + */ + cacheFactory.info = function() { + var info = {}; + forEach(caches, function(cache, cacheId) { + info[cacheId] = cache.info(); + }); + return info; + }; + + + /** + * @ngdoc method + * @name ng.$cacheFactory#get + * @methodOf ng.$cacheFactory + * + * @description + * Get access to a cache object by the `cacheId` used when it was created. + * + * @param {string} cacheId Name or id of a cache to access. + * @returns {object} Cache object identified by the cacheId or undefined if no such cache. + */ + cacheFactory.get = function(cacheId) { + return caches[cacheId]; + }; + + + return cacheFactory; + }; +} + +/** + * @ngdoc object + * @name ng.$templateCache + * + * @description + * The first time a template is used, it is loaded in the template cache for quick retrieval. You + * can load templates directly into the cache in a `script` tag, or by consuming the + * `$templateCache` service directly. + * + * Adding via the `script` tag: + *
+ * 
+ * 
+ * 
+ * 
+ *   ...
+ * 
+ * 
+ * + * **Note:** the `script` tag containing the template does not need to be included in the `head` of + * the document, but it must be below the `ng-app` definition. + * + * Adding via the $templateCache service: + * + *
+ * var myApp = angular.module('myApp', []);
+ * myApp.run(function($templateCache) {
+ *   $templateCache.put('templateId.html', 'This is the content of the template');
+ * });
+ * 
+ * + * To retrieve the template later, simply use it in your HTML: + *
+ * 
+ *
+ * + * or get it via Javascript: + *
+ * $templateCache.get('templateId.html')
+ * 
+ * + * See {@link ng.$cacheFactory $cacheFactory}. + * + */ +function $TemplateCacheProvider() { + this.$get = ['$cacheFactory', function($cacheFactory) { + return $cacheFactory('templates'); + }]; +} + +/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE! + * + * DOM-related variables: + * + * - "node" - DOM Node + * - "element" - DOM Element or Node + * - "$node" or "$element" - jqLite-wrapped node or element + * + * + * Compiler related stuff: + * + * - "linkFn" - linking fn of a single directive + * - "nodeLinkFn" - function that aggregates all linking fns for a particular node + * - "childLinkFn" - function that aggregates all linking fns for child nodes of a particular node + * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList) + */ + + +/** + * @ngdoc function + * @name ng.$compile + * @function + * + * @description + * Compiles a piece of HTML string or DOM into a template and produces a template function, which + * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together. + * + * The compilation is a process of walking the DOM tree and matching DOM elements to + * {@link ng.$compileProvider#methods_directive directives}. + * + *
+ * **Note:** This document is an in-depth reference of all directive options. + * For a gentle introduction to directives with examples of common use cases, + * see the {@link guide/directive directive guide}. + *
+ * + * ## Comprehensive Directive API + * + * There are many different options for a directive. + * + * The difference resides in the return value of the factory function. + * You can either return a "Directive Definition Object" (see below) that defines the directive properties, + * or just the `postLink` function (all other properties will have the default values). + * + *
+ * **Best Practice:** It's recommended to use the "directive definition object" form. + *
+ * + * Here's an example directive declared with a Directive Definition Object: + * + *
+ *   var myModule = angular.module(...);
+ *
+ *   myModule.directive('directiveName', function factory(injectables) {
+ *     var directiveDefinitionObject = {
+ *       priority: 0,
+ *       template: '
', // or // function(tElement, tAttrs) { ... }, + * // or + * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, + * replace: false, + * transclude: false, + * restrict: 'A', + * scope: false, + * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, + * require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], + * compile: function compile(tElement, tAttrs, transclude) { + * return { + * pre: function preLink(scope, iElement, iAttrs, controller) { ... }, + * post: function postLink(scope, iElement, iAttrs, controller) { ... } + * } + * // or + * // return function postLink( ... ) { ... } + * }, + * // or + * // link: { + * // pre: function preLink(scope, iElement, iAttrs, controller) { ... }, + * // post: function postLink(scope, iElement, iAttrs, controller) { ... } + * // } + * // or + * // link: function postLink( ... ) { ... } + * }; + * return directiveDefinitionObject; + * }); + *
+ * + *
+ * **Note:** Any unspecified options will use the default value. You can see the default values below. + *
+ * + * Therefore the above can be simplified as: + * + *
+ *   var myModule = angular.module(...);
+ *
+ *   myModule.directive('directiveName', function factory(injectables) {
+ *     var directiveDefinitionObject = {
+ *       link: function postLink(scope, iElement, iAttrs) { ... }
+ *     };
+ *     return directiveDefinitionObject;
+ *     // or
+ *     // return function postLink(scope, iElement, iAttrs) { ... }
+ *   });
+ * 
+ * + * + * + * ### Directive Definition Object + * + * The directive definition object provides instructions to the {@link api/ng.$compile + * compiler}. The attributes are: + * + * #### `priority` + * When there are multiple directives defined on a single DOM element, sometimes it + * is necessary to specify the order in which the directives are applied. The `priority` is used + * to sort the directives before their `compile` functions get called. Priority is defined as a + * number. Directives with greater numerical `priority` are compiled first. Pre-link functions + * are also run in priority order, but post-link functions are run in reverse order. The order + * of directives with the same priority is undefined. The default priority is `0`. + * + * #### `terminal` + * If set to true then the current `priority` will be the last set of directives + * which will execute (any directives at the current priority will still execute + * as the order of execution on same `priority` is undefined). + * + * #### `scope` + * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the + * same element request a new scope, only one new scope is created. The new scope rule does not + * apply for the root of the template since the root of the template always gets a new scope. + * + * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from + * normal scope in that it does not prototypically inherit from the parent scope. This is useful + * when creating reusable components, which should not accidentally read or modify data in the + * parent scope. + * + * The 'isolate' scope takes an object hash which defines a set of local scope properties + * derived from the parent scope. These local properties are useful for aliasing values for + * templates. Locals definition is a hash of local scope property to its source: + * + * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is + * always a string since DOM attributes are strings. If no `attr` name is specified then the + * attribute name is assumed to be the same as the local name. + * Given `` and widget definition + * of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect + * the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the + * `localName` property on the widget scope. The `name` is read from the parent scope (not + * component scope). + * + * * `=` or `=attr` - set up bi-directional binding between a local scope property and the + * parent scope property of name defined via the value of the `attr` attribute. If no `attr` + * name is specified then the attribute name is assumed to be the same as the local name. + * Given `` and widget definition of + * `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the + * value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected + * in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent + * scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You + * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. + * + * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. + * If no `attr` name is specified then the attribute name is assumed to be the same as the + * local name. Given `` and widget definition of + * `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to + * a function wrapper for the `count = count + value` expression. Often it's desirable to + * pass data from the isolated scope via an expression and to the parent scope, this can be + * done by passing a map of local variable names and values into the expression wrapper fn. + * For example, if the expression is `increment(amount)` then we can specify the amount value + * by calling the `localFn` as `localFn({amount: 22})`. + * + * + * + * #### `controller` + * Controller constructor function. The controller is instantiated before the + * pre-linking phase and it is shared with other directives (see + * `require` attribute). This allows the directives to communicate with each other and augment + * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals: + * + * * `$scope` - Current scope associated with the element + * * `$element` - Current element + * * `$attrs` - Current attributes object for the element + * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope. + * The scope can be overridden by an optional first argument. + * `function([scope], cloneLinkingFn)`. + * + * + * #### `require` + * Require another directive and inject its controller as the fourth argument to the linking function. The + * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the + * injected argument will be an array in corresponding order. If no such directive can be + * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with: + * + * * (no prefix) - Locate the required controller on the current element. Throw an error if not found. + * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found. + * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found. + * * `?^` - Attempt to locate the required controller by searching the element's parentsor pass `null` to the + * `link` fn if not found. + * + * + * #### `controllerAs` + * Controller alias at the directive scope. An alias for the controller so it + * can be referenced at the directive template. The directive needs to define a scope for this + * configuration to be used. Useful in the case when directive is used as component. + * + * + * #### `restrict` + * String of subset of `EACM` which restricts the directive to a specific directive + * declaration style. If omitted, the default (attributes only) is used. + * + * * `E` - Element name: `` + * * `A` - Attribute (default): `
` + * * `C` - Class: `
` + * * `M` - Comment: `` + * + * + * #### `template` + * replace the current element with the contents of the HTML. The replacement process + * migrates all of the attributes / classes from the old element to the new one. See the + * {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive + * Directives Guide} for an example. + * + * You can specify `template` as a string representing the template or as a function which takes + * two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and + * returns a string value representing the template. + * + * + * #### `templateUrl` + * Same as `template` but the template is loaded from the specified URL. Because + * the template loading is asynchronous the compilation/linking is suspended until the template + * is loaded. + * + * You can specify `templateUrl` as a string representing the URL or as a function which takes two + * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns + * a string value representing the url. In either case, the template URL is passed through {@link + * api/ng.$sce#methods_getTrustedResourceUrl $sce.getTrustedResourceUrl}. + * + * + * #### `replace` + * specify where the template should be inserted. Defaults to `false`. + * + * * `true` - the template will replace the current element. + * * `false` - the template will replace the contents of the current element. + * + * + * #### `transclude` + * compile the content of the element and make it available to the directive. + * Typically used with {@link api/ng.directive:ngTransclude + * ngTransclude}. The advantage of transclusion is that the linking function receives a + * transclusion function which is pre-bound to the correct scope. In a typical setup the widget + * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate` + * scope. This makes it possible for the widget to have private state, and the transclusion to + * be bound to the parent (pre-`isolate`) scope. + * + * * `true` - transclude the content of the directive. + * * `'element'` - transclude the whole element including any directives defined at lower priority. + * + * + * #### `compile` + * + *
+ *   function compile(tElement, tAttrs, transclude) { ... }
+ * 
+ * + * The compile function deals with transforming the template DOM. Since most directives do not do + * template transformation, it is not used often. Examples that require compile functions are + * directives that transform template DOM, such as {@link + * api/ng.directive:ngRepeat ngRepeat}, or load the contents + * asynchronously, such as {@link api/ngRoute.directive:ngView ngView}. The + * compile function takes the following arguments. + * + * * `tElement` - template element - The element where the directive has been declared. It is + * safe to do template transformation on the element and child elements only. + * + * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared + * between all directive compile functions. + * + * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)` + * + *
+ * **Note:** The template instance and the link instance may be different objects if the template has + * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that + * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration + * should be done in a linking function rather than in a compile function. + *
+ * + *
+ * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it + * e.g. does not know about the right outer scope. Please use the transclude function that is passed + * to the link function instead. + *
+ + * A compile function can have a return value which can be either a function or an object. + * + * * returning a (post-link) function - is equivalent to registering the linking function via the + * `link` property of the config object when the compile function is empty. + * + * * returning an object with function(s) registered via `pre` and `post` properties - allows you to + * control when a linking function should be called during the linking phase. See info about + * pre-linking and post-linking functions below. + * + * + * #### `link` + * This property is used only if the `compile` property is not defined. + * + *
+ *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
+ * 
+ * + * The link function is responsible for registering DOM listeners as well as updating the DOM. It is + * executed after the template has been cloned. This is where most of the directive logic will be + * put. + * + * * `scope` - {@link api/ng.$rootScope.Scope Scope} - The scope to be used by the + * directive for registering {@link api/ng.$rootScope.Scope#methods_$watch watches}. + * + * * `iElement` - instance element - The element where the directive is to be used. It is safe to + * manipulate the children of the element only in `postLink` function since the children have + * already been linked. + * + * * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared + * between all directive linking functions. + * + * * `controller` - a controller instance - A controller instance if at least one directive on the + * element defines a controller. The controller is shared among all the directives, which allows + * the directives to use the controllers as a communication channel. + * + * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope. + * The scope can be overridden by an optional first argument. This is the same as the `$transclude` + * parameter of directive controllers. + * `function([scope], cloneLinkingFn)`. + * + * + * #### Pre-linking function + * + * Executed before the child elements are linked. Not safe to do DOM transformation since the + * compiler linking function will fail to locate the correct elements for linking. + * + * #### Post-linking function + * + * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function. + * + * + * ### Attributes + * + * The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the + * `link()` or `compile()` functions. It has a variety of uses. + * + * accessing *Normalized attribute names:* + * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. + * the attributes object allows for normalized access to + * the attributes. + * + * * *Directive inter-communication:* All directives share the same instance of the attributes + * object which allows the directives to use the attributes object as inter directive + * communication. + * + * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object + * allowing other directives to read the interpolated value. + * + * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes + * that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also + * the only way to easily get the actual value because during the linking phase the interpolation + * hasn't been evaluated yet and so the value is at this time set to `undefined`. + * + *
+ * function linkingFn(scope, elm, attrs, ctrl) {
+ *   // get the attribute value
+ *   console.log(attrs.ngModel);
+ *
+ *   // change the attribute
+ *   attrs.$set('ngModel', 'new value');
+ *
+ *   // observe changes to interpolated attribute
+ *   attrs.$observe('ngModel', function(value) {
+ *     console.log('ngModel has changed value to ' + value);
+ *   });
+ * }
+ * 
+ * + * Below is an example using `$compileProvider`. + * + *
+ * **Note**: Typically directives are registered with `module.directive`. The example below is + * to illustrate how `$compile` works. + *
+ * + + + +
+
+
+
+
+
+ + it('should auto compile', function() { + expect(element('div[compile]').text()).toBe('Hello Angular'); + input('html').enter('{{name}}!'); + expect(element('div[compile]').text()).toBe('Angular!'); + }); + +
+ + * + * + * @param {string|DOMElement} element Element or HTML string to compile into a template function. + * @param {function(angular.Scope[, cloneAttachFn]} transclude function available to directives. + * @param {number} maxPriority only apply directives lower then given priority (Only effects the + * root element(s), not their children) + * @returns {function(scope[, cloneAttachFn])} a link function which is used to bind template + * (a DOM element/tree) to a scope. Where: + * + * * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to. + * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the + * `template` and call the `cloneAttachFn` function allowing the caller to attach the + * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is + * called as:
`cloneAttachFn(clonedElement, scope)` where: + * + * * `clonedElement` - is a clone of the original `element` passed into the compiler. + * * `scope` - is the current scope with which the linking function is working with. + * + * Calling the linking function returns the element of the template. It is either the original + * element passed in, or the clone of the element if the `cloneAttachFn` is provided. + * + * After linking the view is not updated until after a call to $digest which typically is done by + * Angular automatically. + * + * If you need access to the bound view, there are two ways to do it: + * + * - If you are not asking the linking function to clone the template, create the DOM element(s) + * before you send them to the compiler and keep this reference around. + *
+ *     var element = $compile('

{{total}}

')(scope); + *
+ * + * - if on the other hand, you need the element to be cloned, the view reference from the original + * example would not point to the clone, but rather to the original template that was cloned. In + * this case, you can access the clone via the cloneAttachFn: + *
+ *     var templateHTML = angular.element('

{{total}}

'), + * scope = ....; + * + * var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) { + * //attach the clone to DOM document at the right place + * }); + * + * //now we have reference to the cloned DOM via `clone` + *
+ * + * + * For information on how the compiler works, see the + * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide. + */ + +var $compileMinErr = minErr('$compile'); + +/** + * @ngdoc service + * @name ng.$compileProvider + * @function + * + * @description + */ +$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider']; +function $CompileProvider($provide, $$sanitizeUriProvider) { + var hasDirectives = {}, + Suffix = 'Directive', + COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/, + CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/; + + // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes + // The assumption is that future DOM event attribute names will begin with + // 'on' and be composed of only English letters. + var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/; + + /** + * @ngdoc function + * @name ng.$compileProvider#directive + * @methodOf ng.$compileProvider + * @function + * + * @description + * Register a new directive with the compiler. + * + * @param {string|Object} name Name of the directive in camel-case (i.e. ngBind which + * will match as ng-bind), or an object map of directives where the keys are the + * names and the values are the factories. + * @param {function|Array} directiveFactory An injectable directive factory function. See + * {@link guide/directive} for more info. + * @returns {ng.$compileProvider} Self for chaining. + */ + this.directive = function registerDirective(name, directiveFactory) { + assertNotHasOwnProperty(name, 'directive'); + if (isString(name)) { + assertArg(directiveFactory, 'directiveFactory'); + if (!hasDirectives.hasOwnProperty(name)) { + hasDirectives[name] = []; + $provide.factory(name + Suffix, ['$injector', '$exceptionHandler', + function($injector, $exceptionHandler) { + var directives = []; + forEach(hasDirectives[name], function(directiveFactory, index) { + try { + var directive = $injector.invoke(directiveFactory); + if (isFunction(directive)) { + directive = { compile: valueFn(directive) }; + } else if (!directive.compile && directive.link) { + directive.compile = valueFn(directive.link); + } + directive.priority = directive.priority || 0; + directive.index = index; + directive.name = directive.name || name; + directive.require = directive.require || (directive.controller && directive.name); + directive.restrict = directive.restrict || 'A'; + directives.push(directive); + } catch (e) { + $exceptionHandler(e); + } + }); + return directives; + }]); + } + hasDirectives[name].push(directiveFactory); + } else { + forEach(name, reverseParams(registerDirective)); + } + return this; + }; + + + /** + * @ngdoc function + * @name ng.$compileProvider#aHrefSanitizationWhitelist + * @methodOf ng.$compileProvider + * @function + * + * @description + * Retrieves or overrides the default regular expression that is used for whitelisting of safe + * urls during a[href] sanitization. + * + * The sanitization is a security measure aimed at prevent XSS attacks via html links. + * + * Any url about to be assigned to a[href] via data-binding is first normalized and turned into + * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist` + * regular expression. If a match is found, the original url is written into the dom. Otherwise, + * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. + * + * @param {RegExp=} regexp New regexp to whitelist urls with. + * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for + * chaining otherwise. + */ + this.aHrefSanitizationWhitelist = function(regexp) { + if (isDefined(regexp)) { + $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp); + return this; + } else { + return $$sanitizeUriProvider.aHrefSanitizationWhitelist(); + } + }; + + + /** + * @ngdoc function + * @name ng.$compileProvider#imgSrcSanitizationWhitelist + * @methodOf ng.$compileProvider + * @function + * + * @description + * Retrieves or overrides the default regular expression that is used for whitelisting of safe + * urls during img[src] sanitization. + * + * The sanitization is a security measure aimed at prevent XSS attacks via html links. + * + * Any url about to be assigned to img[src] via data-binding is first normalized and turned into + * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` + * regular expression. If a match is found, the original url is written into the dom. Otherwise, + * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. + * + * @param {RegExp=} regexp New regexp to whitelist urls with. + * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for + * chaining otherwise. + */ + this.imgSrcSanitizationWhitelist = function(regexp) { + if (isDefined(regexp)) { + $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp); + return this; + } else { + return $$sanitizeUriProvider.imgSrcSanitizationWhitelist(); + } + }; + + this.$get = [ + '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse', + '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri', + function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse, + $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) { + + var Attributes = function(element, attr) { + this.$$element = element; + this.$attr = attr || {}; + }; + + Attributes.prototype = { + $normalize: directiveNormalize, + + + /** + * @ngdoc function + * @name ng.$compile.directive.Attributes#$addClass + * @methodOf ng.$compile.directive.Attributes + * @function + * + * @description + * Adds the CSS class value specified by the classVal parameter to the element. If animations + * are enabled then an animation will be triggered for the class addition. + * + * @param {string} classVal The className value that will be added to the element + */ + $addClass : function(classVal) { + if(classVal && classVal.length > 0) { + $animate.addClass(this.$$element, classVal); + } + }, + + /** + * @ngdoc function + * @name ng.$compile.directive.Attributes#$removeClass + * @methodOf ng.$compile.directive.Attributes + * @function + * + * @description + * Removes the CSS class value specified by the classVal parameter from the element. If + * animations are enabled then an animation will be triggered for the class removal. + * + * @param {string} classVal The className value that will be removed from the element + */ + $removeClass : function(classVal) { + if(classVal && classVal.length > 0) { + $animate.removeClass(this.$$element, classVal); + } + }, + + /** + * @ngdoc function + * @name ng.$compile.directive.Attributes#$updateClass + * @methodOf ng.$compile.directive.Attributes + * @function + * + * @description + * Adds and removes the appropriate CSS class values to the element based on the difference + * between the new and old CSS class values (specified as newClasses and oldClasses). + * + * @param {string} newClasses The current CSS className value + * @param {string} oldClasses The former CSS className value + */ + $updateClass : function(newClasses, oldClasses) { + this.$removeClass(tokenDifference(oldClasses, newClasses)); + this.$addClass(tokenDifference(newClasses, oldClasses)); + }, + + /** + * Set a normalized attribute on the element in a way such that all directives + * can share the attribute. This function properly handles boolean attributes. + * @param {string} key Normalized key. (ie ngAttribute) + * @param {string|boolean} value The value to set. If `null` attribute will be deleted. + * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute. + * Defaults to true. + * @param {string=} attrName Optional none normalized name. Defaults to key. + */ + $set: function(key, value, writeAttr, attrName) { + // TODO: decide whether or not to throw an error if "class" + //is set through this function since it may cause $updateClass to + //become unstable. + + var booleanKey = getBooleanAttrName(this.$$element[0], key), + normalizedVal, + nodeName; + + if (booleanKey) { + this.$$element.prop(key, value); + attrName = booleanKey; + } + + this[key] = value; + + // translate normalized key to actual key + if (attrName) { + this.$attr[key] = attrName; + } else { + attrName = this.$attr[key]; + if (!attrName) { + this.$attr[key] = attrName = snake_case(key, '-'); + } + } + + nodeName = nodeName_(this.$$element); + + // sanitize a[href] and img[src] values + if ((nodeName === 'A' && key === 'href') || + (nodeName === 'IMG' && key === 'src')) { + this[key] = value = $$sanitizeUri(value, key === 'src'); + } + + if (writeAttr !== false) { + if (value === null || value === undefined) { + this.$$element.removeAttr(attrName); + } else { + this.$$element.attr(attrName, value); + } + } + + // fire observers + var $$observers = this.$$observers; + $$observers && forEach($$observers[key], function(fn) { + try { + fn(value); + } catch (e) { + $exceptionHandler(e); + } + }); + }, + + + /** + * @ngdoc function + * @name ng.$compile.directive.Attributes#$observe + * @methodOf ng.$compile.directive.Attributes + * @function + * + * @description + * Observes an interpolated attribute. + * + * The observer function will be invoked once during the next `$digest` following + * compilation. The observer is then invoked whenever the interpolated value + * changes. + * + * @param {string} key Normalized key. (ie ngAttribute) . + * @param {function(interpolatedValue)} fn Function that will be called whenever + the interpolated value of the attribute changes. + * See the {@link guide/directive#Attributes Directives} guide for more info. + * @returns {function()} the `fn` parameter. + */ + $observe: function(key, fn) { + var attrs = this, + $$observers = (attrs.$$observers || (attrs.$$observers = {})), + listeners = ($$observers[key] || ($$observers[key] = [])); + + listeners.push(fn); + $rootScope.$evalAsync(function() { + if (!listeners.$$inter) { + // no one registered attribute interpolation function, so lets call it manually + fn(attrs[key]); + } + }); + return fn; + } + }; + + var startSymbol = $interpolate.startSymbol(), + endSymbol = $interpolate.endSymbol(), + denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}') + ? identity + : function denormalizeTemplate(template) { + return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol); + }, + NG_ATTR_BINDING = /^ngAttr[A-Z]/; + + + return compile; + + //================================ + + function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, + previousCompileContext) { + if (!($compileNodes instanceof jqLite)) { + // jquery always rewraps, whereas we need to preserve the original selector so that we can + // modify it. + $compileNodes = jqLite($compileNodes); + } + // We can not compile top level text elements since text nodes can be merged and we will + // not be able to attach scope data to them, so we will wrap them in + forEach($compileNodes, function(node, index){ + if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) { + $compileNodes[index] = node = jqLite(node).wrap('').parent()[0]; + } + }); + var compositeLinkFn = + compileNodes($compileNodes, transcludeFn, $compileNodes, + maxPriority, ignoreDirective, previousCompileContext); + return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){ + assertArg(scope, 'scope'); + // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart + // and sometimes changes the structure of the DOM. + var $linkNode = cloneConnectFn + ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!! + : $compileNodes; + + forEach(transcludeControllers, function(instance, name) { + $linkNode.data('$' + name + 'Controller', instance); + }); + + // Attach scope only to non-text nodes. + for(var i = 0, ii = $linkNode.length; i + addDirective(directives, + directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective); + + // iterate over the attributes + for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes, + j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) { + var attrStartName = false; + var attrEndName = false; + + attr = nAttrs[j]; + if (!msie || msie >= 8 || attr.specified) { + name = attr.name; + // support ngAttr attribute binding + ngAttrName = directiveNormalize(name); + if (NG_ATTR_BINDING.test(ngAttrName)) { + name = snake_case(ngAttrName.substr(6), '-'); + } + + var directiveNName = ngAttrName.replace(/(Start|End)$/, ''); + if (ngAttrName === directiveNName + 'Start') { + attrStartName = name; + attrEndName = name.substr(0, name.length - 5) + 'end'; + name = name.substr(0, name.length - 6); + } + + nName = directiveNormalize(name.toLowerCase()); + attrsMap[nName] = name; + attrs[nName] = value = trim((msie && name == 'href') + ? decodeURIComponent(node.getAttribute(name, 2)) + : attr.value); + if (getBooleanAttrName(node, nName)) { + attrs[nName] = true; // presence means true + } + addAttrInterpolateDirective(node, directives, value, nName); + addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName, + attrEndName); + } + } + + // use class as directive + className = node.className; + if (isString(className) && className !== '') { + while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) { + nName = directiveNormalize(match[2]); + if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) { + attrs[nName] = trim(match[3]); + } + className = className.substr(match.index + match[0].length); + } + } + break; + case 3: /* Text Node */ + addTextInterpolateDirective(directives, node.nodeValue); + break; + case 8: /* Comment */ + try { + match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue); + if (match) { + nName = directiveNormalize(match[1]); + if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) { + attrs[nName] = trim(match[2]); + } + } + } catch (e) { + // turns out that under some circumstances IE9 throws errors when one attempts to read + // comment's node value. + // Just ignore it and continue. (Can't seem to reproduce in test case.) + } + break; + } + + directives.sort(byPriority); + return directives; + } + + /** + * Given a node with an directive-start it collects all of the siblings until it finds + * directive-end. + * @param node + * @param attrStart + * @param attrEnd + * @returns {*} + */ + function groupScan(node, attrStart, attrEnd) { + var nodes = []; + var depth = 0; + if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) { + var startNode = node; + do { + if (!node) { + throw $compileMinErr('uterdir', + "Unterminated attribute, found '{0}' but no matching '{1}' found.", + attrStart, attrEnd); + } + if (node.nodeType == 1 /** Element **/) { + if (node.hasAttribute(attrStart)) depth++; + if (node.hasAttribute(attrEnd)) depth--; + } + nodes.push(node); + node = node.nextSibling; + } while (depth > 0); + } else { + nodes.push(node); + } + + return jqLite(nodes); + } + + /** + * Wrapper for linking function which converts normal linking function into a grouped + * linking function. + * @param linkFn + * @param attrStart + * @param attrEnd + * @returns {Function} + */ + function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) { + return function(scope, element, attrs, controllers, transcludeFn) { + element = groupScan(element[0], attrStart, attrEnd); + return linkFn(scope, element, attrs, controllers, transcludeFn); + }; + } + + /** + * Once the directives have been collected, their compile functions are executed. This method + * is responsible for inlining directive templates as well as terminating the application + * of the directives if the terminal directive has been reached. + * + * @param {Array} directives Array of collected directives to execute their compile function. + * this needs to be pre-sorted by priority order. + * @param {Node} compileNode The raw DOM node to apply the compile functions to + * @param {Object} templateAttrs The shared attribute function + * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the + * scope argument is auto-generated to the new + * child of the transcluded parent scope. + * @param {JQLite} jqCollection If we are working on the root of the compile tree then this + * argument has the root jqLite array so that we can replace nodes + * on it. + * @param {Object=} originalReplaceDirective An optional directive that will be ignored when + * compiling the transclusion. + * @param {Array.} preLinkFns + * @param {Array.} postLinkFns + * @param {Object} previousCompileContext Context used for previous compilation of the current + * node + * @returns linkFn + */ + function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, + jqCollection, originalReplaceDirective, preLinkFns, postLinkFns, + previousCompileContext) { + previousCompileContext = previousCompileContext || {}; + + var terminalPriority = -Number.MAX_VALUE, + newScopeDirective, + controllerDirectives = previousCompileContext.controllerDirectives, + newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective, + templateDirective = previousCompileContext.templateDirective, + nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective, + hasTranscludeDirective = false, + hasElementTranscludeDirective = false, + $compileNode = templateAttrs.$$element = jqLite(compileNode), + directive, + directiveName, + $template, + replaceDirective = originalReplaceDirective, + childTranscludeFn = transcludeFn, + linkFn, + directiveValue; + + // executes all directives on the current element + for(var i = 0, ii = directives.length; i < ii; i++) { + directive = directives[i]; + var attrStart = directive.$$start; + var attrEnd = directive.$$end; + + // collect multiblock sections + if (attrStart) { + $compileNode = groupScan(compileNode, attrStart, attrEnd); + } + $template = undefined; + + if (terminalPriority > directive.priority) { + break; // prevent further processing of directives + } + + if (directiveValue = directive.scope) { + newScopeDirective = newScopeDirective || directive; + + // skip the check for directives with async templates, we'll check the derived sync + // directive when the template arrives + if (!directive.templateUrl) { + assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive, + $compileNode); + if (isObject(directiveValue)) { + newIsolateScopeDirective = directive; + } + } + } + + directiveName = directive.name; + + if (!directive.templateUrl && directive.controller) { + directiveValue = directive.controller; + controllerDirectives = controllerDirectives || {}; + assertNoDuplicate("'" + directiveName + "' controller", + controllerDirectives[directiveName], directive, $compileNode); + controllerDirectives[directiveName] = directive; + } + + if (directiveValue = directive.transclude) { + hasTranscludeDirective = true; + + // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion. + // This option should only be used by directives that know how to how to safely handle element transclusion, + // where the transcluded nodes are added or replaced after linking. + if (!directive.$$tlb) { + assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode); + nonTlbTranscludeDirective = directive; + } + + if (directiveValue == 'element') { + hasElementTranscludeDirective = true; + terminalPriority = directive.priority; + $template = groupScan(compileNode, attrStart, attrEnd); + $compileNode = templateAttrs.$$element = + jqLite(document.createComment(' ' + directiveName + ': ' + + templateAttrs[directiveName] + ' ')); + compileNode = $compileNode[0]; + replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode); + + childTranscludeFn = compile($template, transcludeFn, terminalPriority, + replaceDirective && replaceDirective.name, { + // Don't pass in: + // - controllerDirectives - otherwise we'll create duplicates controllers + // - newIsolateScopeDirective or templateDirective - combining templates with + // element transclusion doesn't make sense. + // + // We need only nonTlbTranscludeDirective so that we prevent putting transclusion + // on the same element more than once. + nonTlbTranscludeDirective: nonTlbTranscludeDirective + }); + } else { + $template = jqLite(jqLiteClone(compileNode)).contents(); + $compileNode.html(''); // clear contents + childTranscludeFn = compile($template, transcludeFn); + } + } + + if (directive.template) { + assertNoDuplicate('template', templateDirective, directive, $compileNode); + templateDirective = directive; + + directiveValue = (isFunction(directive.template)) + ? directive.template($compileNode, templateAttrs) + : directive.template; + + directiveValue = denormalizeTemplate(directiveValue); + + if (directive.replace) { + replaceDirective = directive; + $template = jqLite('
' + + trim(directiveValue) + + '
').contents(); + compileNode = $template[0]; + + if ($template.length != 1 || compileNode.nodeType !== 1) { + throw $compileMinErr('tplrt', + "Template for directive '{0}' must have exactly one root element. {1}", + directiveName, ''); + } + + replaceWith(jqCollection, $compileNode, compileNode); + + var newTemplateAttrs = {$attr: {}}; + + // combine directives from the original node and from the template: + // - take the array of directives for this element + // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed) + // - collect directives from the template and sort them by priority + // - combine directives as: processed + template + unprocessed + var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs); + var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1)); + + if (newIsolateScopeDirective) { + markDirectivesAsIsolate(templateDirectives); + } + directives = directives.concat(templateDirectives).concat(unprocessedDirectives); + mergeTemplateAttributes(templateAttrs, newTemplateAttrs); + + ii = directives.length; + } else { + $compileNode.html(directiveValue); + } + } + + if (directive.templateUrl) { + assertNoDuplicate('template', templateDirective, directive, $compileNode); + templateDirective = directive; + + if (directive.replace) { + replaceDirective = directive; + } + + nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode, + templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, { + controllerDirectives: controllerDirectives, + newIsolateScopeDirective: newIsolateScopeDirective, + templateDirective: templateDirective, + nonTlbTranscludeDirective: nonTlbTranscludeDirective + }); + ii = directives.length; + } else if (directive.compile) { + try { + linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn); + if (isFunction(linkFn)) { + addLinkFns(null, linkFn, attrStart, attrEnd); + } else if (linkFn) { + addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd); + } + } catch (e) { + $exceptionHandler(e, startingTag($compileNode)); + } + } + + if (directive.terminal) { + nodeLinkFn.terminal = true; + terminalPriority = Math.max(terminalPriority, directive.priority); + } + + } + + nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true; + nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn; + + // might be normal or delayed nodeLinkFn depending on if templateUrl is present + return nodeLinkFn; + + //////////////////// + + function addLinkFns(pre, post, attrStart, attrEnd) { + if (pre) { + if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd); + pre.require = directive.require; + if (newIsolateScopeDirective === directive || directive.$$isolateScope) { + pre = cloneAndAnnotateFn(pre, {isolateScope: true}); + } + preLinkFns.push(pre); + } + if (post) { + if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd); + post.require = directive.require; + if (newIsolateScopeDirective === directive || directive.$$isolateScope) { + post = cloneAndAnnotateFn(post, {isolateScope: true}); + } + postLinkFns.push(post); + } + } + + + function getControllers(require, $element, elementControllers) { + var value, retrievalMethod = 'data', optional = false; + if (isString(require)) { + while((value = require.charAt(0)) == '^' || value == '?') { + require = require.substr(1); + if (value == '^') { + retrievalMethod = 'inheritedData'; + } + optional = optional || value == '?'; + } + value = null; + + if (elementControllers && retrievalMethod === 'data') { + value = elementControllers[require]; + } + value = value || $element[retrievalMethod]('$' + require + 'Controller'); + + if (!value && !optional) { + throw $compileMinErr('ctreq', + "Controller '{0}', required by directive '{1}', can't be found!", + require, directiveName); + } + return value; + } else if (isArray(require)) { + value = []; + forEach(require, function(require) { + value.push(getControllers(require, $element, elementControllers)); + }); + } + return value; + } + + + function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) { + var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn; + + if (compileNode === linkNode) { + attrs = templateAttrs; + } else { + attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr)); + } + $element = attrs.$$element; + + if (newIsolateScopeDirective) { + var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/; + var $linkNode = jqLite(linkNode); + + isolateScope = scope.$new(true); + + if (templateDirective && (templateDirective === newIsolateScopeDirective.$$originalDirective)) { + $linkNode.data('$isolateScope', isolateScope) ; + } else { + $linkNode.data('$isolateScopeNoTemplate', isolateScope); + } + + + + safeAddClass($linkNode, 'ng-isolate-scope'); + + forEach(newIsolateScopeDirective.scope, function(definition, scopeName) { + var match = definition.match(LOCAL_REGEXP) || [], + attrName = match[3] || scopeName, + optional = (match[2] == '?'), + mode = match[1], // @, =, or & + lastValue, + parentGet, parentSet; + + isolateScope.$$isolateBindings[scopeName] = mode + attrName; + + switch (mode) { + + case '@': + attrs.$observe(attrName, function(value) { + isolateScope[scopeName] = value; + }); + attrs.$$observers[attrName].$$scope = scope; + if( attrs[attrName] ) { + // If the attribute has been provided then we trigger an interpolation to ensure + // the value is there for use in the link fn + isolateScope[scopeName] = $interpolate(attrs[attrName])(scope); + } + break; + + case '=': + if (optional && !attrs[attrName]) { + return; + } + parentGet = $parse(attrs[attrName]); + parentSet = parentGet.assign || function() { + // reset the change, or we will throw this exception on every $digest + lastValue = isolateScope[scopeName] = parentGet(scope); + throw $compileMinErr('nonassign', + "Expression '{0}' used with directive '{1}' is non-assignable!", + attrs[attrName], newIsolateScopeDirective.name); + }; + lastValue = isolateScope[scopeName] = parentGet(scope); + isolateScope.$watch(function parentValueWatch() { + var parentValue = parentGet(scope); + + if (parentValue !== isolateScope[scopeName]) { + // we are out of sync and need to copy + if (parentValue !== lastValue) { + // parent changed and it has precedence + lastValue = isolateScope[scopeName] = parentValue; + } else { + // if the parent can be assigned then do so + parentSet(scope, parentValue = lastValue = isolateScope[scopeName]); + } + } + return parentValue; + }); + break; + + case '&': + parentGet = $parse(attrs[attrName]); + isolateScope[scopeName] = function(locals) { + return parentGet(scope, locals); + }; + break; + + default: + throw $compileMinErr('iscp', + "Invalid isolate scope definition for directive '{0}'." + + " Definition: {... {1}: '{2}' ...}", + newIsolateScopeDirective.name, scopeName, definition); + } + }); + } + transcludeFn = boundTranscludeFn && controllersBoundTransclude; + if (controllerDirectives) { + forEach(controllerDirectives, function(directive) { + var locals = { + $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope, + $element: $element, + $attrs: attrs, + $transclude: transcludeFn + }, controllerInstance; + + controller = directive.controller; + if (controller == '@') { + controller = attrs[directive.name]; + } + + controllerInstance = $controller(controller, locals); + // For directives with element transclusion the element is a comment, + // but jQuery .data doesn't support attaching data to comment nodes as it's hard to + // clean up (http://bugs.jquery.com/ticket/8335). + // Instead, we save the controllers for the element in a local hash and attach to .data + // later, once we have the actual element. + elementControllers[directive.name] = controllerInstance; + if (!hasElementTranscludeDirective) { + $element.data('$' + directive.name + 'Controller', controllerInstance); + } + + if (directive.controllerAs) { + locals.$scope[directive.controllerAs] = controllerInstance; + } + }); + } + + // PRELINKING + for(i = 0, ii = preLinkFns.length; i < ii; i++) { + try { + linkFn = preLinkFns[i]; + linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs, + linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn); + } catch (e) { + $exceptionHandler(e, startingTag($element)); + } + } + + // RECURSION + // We only pass the isolate scope, if the isolate directive has a template, + // otherwise the child elements do not belong to the isolate directive. + var scopeToChild = scope; + if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) { + scopeToChild = isolateScope; + } + childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn); + + // POSTLINKING + for(i = postLinkFns.length - 1; i >= 0; i--) { + try { + linkFn = postLinkFns[i]; + linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs, + linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn); + } catch (e) { + $exceptionHandler(e, startingTag($element)); + } + } + + // This is the function that is injected as `$transclude`. + function controllersBoundTransclude(scope, cloneAttachFn) { + var transcludeControllers; + + // no scope passed + if (arguments.length < 2) { + cloneAttachFn = scope; + scope = undefined; + } + + if (hasElementTranscludeDirective) { + transcludeControllers = elementControllers; + } + + return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers); + } + } + } + + function markDirectivesAsIsolate(directives) { + // mark all directives as needing isolate scope. + for (var j = 0, jj = directives.length; j < jj; j++) { + directives[j] = inherit(directives[j], {$$isolateScope: true}); + } + } + + /** + * looks up the directive and decorates it with exception handling and proper parameters. We + * call this the boundDirective. + * + * @param {string} name name of the directive to look up. + * @param {string} location The directive must be found in specific format. + * String containing any of theses characters: + * + * * `E`: element name + * * `A': attribute + * * `C`: class + * * `M`: comment + * @returns true if directive was added. + */ + function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName, + endAttrName) { + if (name === ignoreDirective) return null; + var match = null; + if (hasDirectives.hasOwnProperty(name)) { + for(var directive, directives = $injector.get(name + Suffix), + i = 0, ii = directives.length; i directive.priority) && + directive.restrict.indexOf(location) != -1) { + if (startAttrName) { + directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName}); + } + tDirectives.push(directive); + match = directive; + } + } catch(e) { $exceptionHandler(e); } + } + } + return match; + } + + + /** + * When the element is replaced with HTML template then the new attributes + * on the template need to be merged with the existing attributes in the DOM. + * The desired effect is to have both of the attributes present. + * + * @param {object} dst destination attributes (original DOM) + * @param {object} src source attributes (from the directive template) + */ + function mergeTemplateAttributes(dst, src) { + var srcAttr = src.$attr, + dstAttr = dst.$attr, + $element = dst.$$element; + + // reapply the old attributes to the new element + forEach(dst, function(value, key) { + if (key.charAt(0) != '$') { + if (src[key]) { + value += (key === 'style' ? ';' : ' ') + src[key]; + } + dst.$set(key, value, true, srcAttr[key]); + } + }); + + // copy the new attributes on the old attrs object + forEach(src, function(value, key) { + if (key == 'class') { + safeAddClass($element, value); + dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value; + } else if (key == 'style') { + $element.attr('style', $element.attr('style') + ';' + value); + dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value; + // `dst` will never contain hasOwnProperty as DOM parser won't let it. + // You will get an "InvalidCharacterError: DOM Exception 5" error if you + // have an attribute like "has-own-property" or "data-has-own-property", etc. + } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) { + dst[key] = value; + dstAttr[key] = srcAttr[key]; + } + }); + } + + + function compileTemplateUrl(directives, $compileNode, tAttrs, + $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) { + var linkQueue = [], + afterTemplateNodeLinkFn, + afterTemplateChildLinkFn, + beforeTemplateCompileNode = $compileNode[0], + origAsyncDirective = directives.shift(), + // The fact that we have to copy and patch the directive seems wrong! + derivedSyncDirective = extend({}, origAsyncDirective, { + templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective + }), + templateUrl = (isFunction(origAsyncDirective.templateUrl)) + ? origAsyncDirective.templateUrl($compileNode, tAttrs) + : origAsyncDirective.templateUrl; + + $compileNode.html(''); + + $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}). + success(function(content) { + var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn; + + content = denormalizeTemplate(content); + + if (origAsyncDirective.replace) { + $template = jqLite('
' + trim(content) + '
').contents(); + compileNode = $template[0]; + + if ($template.length != 1 || compileNode.nodeType !== 1) { + throw $compileMinErr('tplrt', + "Template for directive '{0}' must have exactly one root element. {1}", + origAsyncDirective.name, templateUrl); + } + + tempTemplateAttrs = {$attr: {}}; + replaceWith($rootElement, $compileNode, compileNode); + var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs); + + if (isObject(origAsyncDirective.scope)) { + markDirectivesAsIsolate(templateDirectives); + } + directives = templateDirectives.concat(directives); + mergeTemplateAttributes(tAttrs, tempTemplateAttrs); + } else { + compileNode = beforeTemplateCompileNode; + $compileNode.html(content); + } + + directives.unshift(derivedSyncDirective); + + afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, + childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns, + previousCompileContext); + forEach($rootElement, function(node, i) { + if (node == compileNode) { + $rootElement[i] = $compileNode[0]; + } + }); + afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn); + + + while(linkQueue.length) { + var scope = linkQueue.shift(), + beforeTemplateLinkNode = linkQueue.shift(), + linkRootElement = linkQueue.shift(), + boundTranscludeFn = linkQueue.shift(), + linkNode = $compileNode[0]; + + if (beforeTemplateLinkNode !== beforeTemplateCompileNode) { + // it was cloned therefore we have to clone as well. + linkNode = jqLiteClone(compileNode); + replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode); + } + if (afterTemplateNodeLinkFn.transclude) { + childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude); + } else { + childBoundTranscludeFn = boundTranscludeFn; + } + afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, + childBoundTranscludeFn); + } + linkQueue = null; + }). + error(function(response, code, headers, config) { + throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url); + }); + + return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) { + if (linkQueue) { + linkQueue.push(scope); + linkQueue.push(node); + linkQueue.push(rootElement); + linkQueue.push(boundTranscludeFn); + } else { + afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn); + } + }; + } + + + /** + * Sorting function for bound directives. + */ + function byPriority(a, b) { + var diff = b.priority - a.priority; + if (diff !== 0) return diff; + if (a.name !== b.name) return (a.name < b.name) ? -1 : 1; + return a.index - b.index; + } + + + function assertNoDuplicate(what, previousDirective, directive, element) { + if (previousDirective) { + throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}', + previousDirective.name, directive.name, what, startingTag(element)); + } + } + + + function addTextInterpolateDirective(directives, text) { + var interpolateFn = $interpolate(text, true); + if (interpolateFn) { + directives.push({ + priority: 0, + compile: valueFn(function textInterpolateLinkFn(scope, node) { + var parent = node.parent(), + bindings = parent.data('$binding') || []; + bindings.push(interpolateFn); + safeAddClass(parent.data('$binding', bindings), 'ng-binding'); + scope.$watch(interpolateFn, function interpolateFnWatchAction(value) { + node[0].nodeValue = value; + }); + }) + }); + } + } + + + function getTrustedContext(node, attrNormalizedName) { + if (attrNormalizedName == "srcdoc") { + return $sce.HTML; + } + var tag = nodeName_(node); + // maction[xlink:href] can source SVG. It's not limited to . + if (attrNormalizedName == "xlinkHref" || + (tag == "FORM" && attrNormalizedName == "action") || + (tag != "IMG" && (attrNormalizedName == "src" || + attrNormalizedName == "ngSrc"))) { + return $sce.RESOURCE_URL; + } + } + + + function addAttrInterpolateDirective(node, directives, value, name) { + var interpolateFn = $interpolate(value, true); + + // no interpolation found -> ignore + if (!interpolateFn) return; + + + if (name === "multiple" && nodeName_(node) === "SELECT") { + throw $compileMinErr("selmulti", + "Binding to the 'multiple' attribute is not supported. Element: {0}", + startingTag(node)); + } + + directives.push({ + priority: 100, + compile: function() { + return { + pre: function attrInterpolatePreLinkFn(scope, element, attr) { + var $$observers = (attr.$$observers || (attr.$$observers = {})); + + if (EVENT_HANDLER_ATTR_REGEXP.test(name)) { + throw $compileMinErr('nodomevents', + "Interpolations for HTML DOM event attributes are disallowed. Please use the " + + "ng- versions (such as ng-click instead of onclick) instead."); + } + + // we need to interpolate again, in case the attribute value has been updated + // (e.g. by another directive's compile function) + interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name)); + + // if attribute was updated so that there is no interpolation going on we don't want to + // register any observers + if (!interpolateFn) return; + + // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the + // actual attr value + attr[name] = interpolateFn(scope); + ($$observers[name] || ($$observers[name] = [])).$$inter = true; + (attr.$$observers && attr.$$observers[name].$$scope || scope). + $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) { + //special case for class attribute addition + removal + //so that class changes can tap into the animation + //hooks provided by the $animate service. Be sure to + //skip animations when the first digest occurs (when + //both the new and the old values are the same) since + //the CSS classes are the non-interpolated values + if(name === 'class' && newValue != oldValue) { + attr.$updateClass(newValue, oldValue); + } else { + attr.$set(name, newValue); + } + }); + } + }; + } + }); + } + + + /** + * This is a special jqLite.replaceWith, which can replace items which + * have no parents, provided that the containing jqLite collection is provided. + * + * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes + * in the root of the tree. + * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep + * the shell, but replace its DOM node reference. + * @param {Node} newNode The new DOM node. + */ + function replaceWith($rootElement, elementsToRemove, newNode) { + var firstElementToRemove = elementsToRemove[0], + removeCount = elementsToRemove.length, + parent = firstElementToRemove.parentNode, + i, ii; + + if ($rootElement) { + for(i = 0, ii = $rootElement.length; i < ii; i++) { + if ($rootElement[i] == firstElementToRemove) { + $rootElement[i++] = newNode; + for (var j = i, j2 = j + removeCount - 1, + jj = $rootElement.length; + j < jj; j++, j2++) { + if (j2 < jj) { + $rootElement[j] = $rootElement[j2]; + } else { + delete $rootElement[j]; + } + } + $rootElement.length -= removeCount - 1; + break; + } + } + } + + if (parent) { + parent.replaceChild(newNode, firstElementToRemove); + } + var fragment = document.createDocumentFragment(); + fragment.appendChild(firstElementToRemove); + newNode[jqLite.expando] = firstElementToRemove[jqLite.expando]; + for (var k = 1, kk = elementsToRemove.length; k < kk; k++) { + var element = elementsToRemove[k]; + jqLite(element).remove(); // must do this way to clean up expando + fragment.appendChild(element); + delete elementsToRemove[k]; + } + + elementsToRemove[0] = newNode; + elementsToRemove.length = 1; + } + + + function cloneAndAnnotateFn(fn, annotation) { + return extend(function() { return fn.apply(null, arguments); }, fn, annotation); + } + }]; +} + +var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i; +/** + * Converts all accepted directives format into proper directive name. + * All of these will become 'myDirective': + * my:Directive + * my-directive + * x-my-directive + * data-my:directive + * + * Also there is special case for Moz prefix starting with upper case letter. + * @param name Name to normalize + */ +function directiveNormalize(name) { + return camelCase(name.replace(PREFIX_REGEXP, '')); +} + +/** + * @ngdoc object + * @name ng.$compile.directive.Attributes + * + * @description + * A shared object between directive compile / linking functions which contains normalized DOM + * element attributes. The values reflect current binding state `{{ }}`. The normalization is + * needed since all of these are treated as equivalent in Angular: + * + * + */ + +/** + * @ngdoc property + * @name ng.$compile.directive.Attributes#$attr + * @propertyOf ng.$compile.directive.Attributes + * @returns {object} A map of DOM element attribute names to the normalized name. This is + * needed to do reverse lookup from normalized name back to actual name. + */ + + +/** + * @ngdoc function + * @name ng.$compile.directive.Attributes#$set + * @methodOf ng.$compile.directive.Attributes + * @function + * + * @description + * Set DOM element attribute value. + * + * + * @param {string} name Normalized element attribute name of the property to modify. The name is + * revers translated using the {@link ng.$compile.directive.Attributes#$attr $attr} + * property to the original name. + * @param {string} value Value to set the attribute to. The value can be an interpolated string. + */ + + + +/** + * Closure compiler type information + */ + +function nodesetLinkingFn( + /* angular.Scope */ scope, + /* NodeList */ nodeList, + /* Element */ rootElement, + /* function(Function) */ boundTranscludeFn +){} + +function directiveLinkingFn( + /* nodesetLinkingFn */ nodesetLinkingFn, + /* angular.Scope */ scope, + /* Node */ node, + /* Element */ rootElement, + /* function(Function) */ boundTranscludeFn +){} + +function tokenDifference(str1, str2) { + var values = '', + tokens1 = str1.split(/\s+/), + tokens2 = str2.split(/\s+/); + + outer: + for(var i = 0; i < tokens1.length; i++) { + var token = tokens1[i]; + for(var j = 0; j < tokens2.length; j++) { + if(token == tokens2[j]) continue outer; + } + values += (values.length > 0 ? ' ' : '') + token; + } + return values; +} + +/** + * @ngdoc object + * @name ng.$controllerProvider + * @description + * The {@link ng.$controller $controller service} is used by Angular to create new + * controllers. + * + * This provider allows controller registration via the + * {@link ng.$controllerProvider#methods_register register} method. + */ +function $ControllerProvider() { + var controllers = {}, + CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/; + + + /** + * @ngdoc function + * @name ng.$controllerProvider#register + * @methodOf ng.$controllerProvider + * @param {string|Object} name Controller name, or an object map of controllers where the keys are + * the names and the values are the constructors. + * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI + * annotations in the array notation). + */ + this.register = function(name, constructor) { + assertNotHasOwnProperty(name, 'controller'); + if (isObject(name)) { + extend(controllers, name); + } else { + controllers[name] = constructor; + } + }; + + + this.$get = ['$injector', '$window', function($injector, $window) { + + /** + * @ngdoc function + * @name ng.$controller + * @requires $injector + * + * @param {Function|string} constructor If called with a function then it's considered to be the + * controller constructor function. Otherwise it's considered to be a string which is used + * to retrieve the controller constructor using the following steps: + * + * * check if a controller with given name is registered via `$controllerProvider` + * * check if evaluating the string on the current scope returns a constructor + * * check `window[constructor]` on the global `window` object + * + * @param {Object} locals Injection locals for Controller. + * @return {Object} Instance of given controller. + * + * @description + * `$controller` service is responsible for instantiating controllers. + * + * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into + * a service, so that one can override this service with {@link https://gist.github.com/1649788 + * BC version}. + */ + return function(expression, locals) { + var instance, match, constructor, identifier; + + if(isString(expression)) { + match = expression.match(CNTRL_REG), + constructor = match[1], + identifier = match[3]; + expression = controllers.hasOwnProperty(constructor) + ? controllers[constructor] + : getter(locals.$scope, constructor, true) || getter($window, constructor, true); + + assertArgFn(expression, constructor, true); + } + + instance = $injector.instantiate(expression, locals); + + if (identifier) { + if (!(locals && typeof locals.$scope == 'object')) { + throw minErr('$controller')('noscp', + "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.", + constructor || expression.name, identifier); + } + + locals.$scope[identifier] = instance; + } + + return instance; + }; + }]; +} + +/** + * @ngdoc object + * @name ng.$document + * @requires $window + * + * @description + * A {@link angular.element jQuery (lite)}-wrapped reference to the browser's `window.document` + * element. + */ +function $DocumentProvider(){ + this.$get = ['$window', function(window){ + return jqLite(window.document); + }]; +} + +/** + * @ngdoc function + * @name ng.$exceptionHandler + * @requires $log + * + * @description + * Any uncaught exception in angular expressions is delegated to this service. + * The default implementation simply delegates to `$log.error` which logs it into + * the browser console. + * + * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by + * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing. + * + * ## Example: + * + *
+ *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
+ *     return function (exception, cause) {
+ *       exception.message += ' (caused by "' + cause + '")';
+ *       throw exception;
+ *     };
+ *   });
+ * 
+ * + * This example will override the normal action of `$exceptionHandler`, to make angular + * exceptions fail hard when they happen, instead of just logging to the console. + * + * @param {Error} exception Exception associated with the error. + * @param {string=} cause optional information about the context in which + * the error was thrown. + * + */ +function $ExceptionHandlerProvider() { + this.$get = ['$log', function($log) { + return function(exception, cause) { + $log.error.apply($log, arguments); + }; + }]; +} + +/** + * Parse headers into key value object + * + * @param {string} headers Raw headers as a string + * @returns {Object} Parsed headers as key value object + */ +function parseHeaders(headers) { + var parsed = {}, key, val, i; + + if (!headers) return parsed; + + forEach(headers.split('\n'), function(line) { + i = line.indexOf(':'); + key = lowercase(trim(line.substr(0, i))); + val = trim(line.substr(i + 1)); + + if (key) { + if (parsed[key]) { + parsed[key] += ', ' + val; + } else { + parsed[key] = val; + } + } + }); + + return parsed; +} + + +/** + * Returns a function that provides access to parsed headers. + * + * Headers are lazy parsed when first requested. + * @see parseHeaders + * + * @param {(string|Object)} headers Headers to provide access to. + * @returns {function(string=)} Returns a getter function which if called with: + * + * - if called with single an argument returns a single header value or null + * - if called with no arguments returns an object containing all headers. + */ +function headersGetter(headers) { + var headersObj = isObject(headers) ? headers : undefined; + + return function(name) { + if (!headersObj) headersObj = parseHeaders(headers); + + if (name) { + return headersObj[lowercase(name)] || null; + } + + return headersObj; + }; +} + + +/** + * Chain all given functions + * + * This function is used for both request and response transforming + * + * @param {*} data Data to transform. + * @param {function(string=)} headers Http headers getter fn. + * @param {(function|Array.)} fns Function or an array of functions. + * @returns {*} Transformed data. + */ +function transformData(data, headers, fns) { + if (isFunction(fns)) + return fns(data, headers); + + forEach(fns, function(fn) { + data = fn(data, headers); + }); + + return data; +} + + +function isSuccess(status) { + return 200 <= status && status < 300; +} + + +function $HttpProvider() { + var JSON_START = /^\s*(\[|\{[^\{])/, + JSON_END = /[\}\]]\s*$/, + PROTECTION_PREFIX = /^\)\]\}',?\n/, + CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'}; + + var defaults = this.defaults = { + // transform incoming response data + transformResponse: [function(data) { + if (isString(data)) { + // strip json vulnerability protection prefix + data = data.replace(PROTECTION_PREFIX, ''); + if (JSON_START.test(data) && JSON_END.test(data)) + data = fromJson(data); + } + return data; + }], + + // transform outgoing request data + transformRequest: [function(d) { + return isObject(d) && !isFile(d) ? toJson(d) : d; + }], + + // default headers + headers: { + common: { + 'Accept': 'application/json, text/plain, */*' + }, + post: CONTENT_TYPE_APPLICATION_JSON, + put: CONTENT_TYPE_APPLICATION_JSON, + patch: CONTENT_TYPE_APPLICATION_JSON + }, + + xsrfCookieName: 'XSRF-TOKEN', + xsrfHeaderName: 'X-XSRF-TOKEN' + }; + + /** + * Are ordered by request, i.e. they are applied in the same order as the + * array, on request, but reverse order, on response. + */ + var interceptorFactories = this.interceptors = []; + + /** + * For historical reasons, response interceptors are ordered by the order in which + * they are applied to the response. (This is the opposite of interceptorFactories) + */ + var responseInterceptorFactories = this.responseInterceptors = []; + + this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector', + function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) { + + var defaultCache = $cacheFactory('$http'); + + /** + * Interceptors stored in reverse order. Inner interceptors before outer interceptors. + * The reversal is needed so that we can build up the interception chain around the + * server request. + */ + var reversedInterceptors = []; + + forEach(interceptorFactories, function(interceptorFactory) { + reversedInterceptors.unshift(isString(interceptorFactory) + ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory)); + }); + + forEach(responseInterceptorFactories, function(interceptorFactory, index) { + var responseFn = isString(interceptorFactory) + ? $injector.get(interceptorFactory) + : $injector.invoke(interceptorFactory); + + /** + * Response interceptors go before "around" interceptors (no real reason, just + * had to pick one.) But they are already reversed, so we can't use unshift, hence + * the splice. + */ + reversedInterceptors.splice(index, 0, { + response: function(response) { + return responseFn($q.when(response)); + }, + responseError: function(response) { + return responseFn($q.reject(response)); + } + }); + }); + + + /** + * @ngdoc function + * @name ng.$http + * @requires $httpBackend + * @requires $browser + * @requires $cacheFactory + * @requires $rootScope + * @requires $q + * @requires $injector + * + * @description + * The `$http` service is a core Angular service that facilitates communication with the remote + * HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest + * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}. + * + * For unit testing applications that use `$http` service, see + * {@link ngMock.$httpBackend $httpBackend mock}. + * + * For a higher level of abstraction, please check out the {@link ngResource.$resource + * $resource} service. + * + * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by + * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage + * it is important to familiarize yourself with these APIs and the guarantees they provide. + * + * + * # General usage + * The `$http` service is a function which takes a single argument — a configuration object — + * that is used to generate an HTTP request and returns a {@link ng.$q promise} + * with two $http specific methods: `success` and `error`. + * + *
+     *   $http({method: 'GET', url: '/someUrl'}).
+     *     success(function(data, status, headers, config) {
+     *       // this callback will be called asynchronously
+     *       // when the response is available
+     *     }).
+     *     error(function(data, status, headers, config) {
+     *       // called asynchronously if an error occurs
+     *       // or server returns response with an error status.
+     *     });
+     * 
+ * + * Since the returned value of calling the $http function is a `promise`, you can also use + * the `then` method to register callbacks, and these callbacks will receive a single argument – + * an object representing the response. See the API signature and type info below for more + * details. + * + * A response status code between 200 and 299 is considered a success status and + * will result in the success callback being called. Note that if the response is a redirect, + * XMLHttpRequest will transparently follow it, meaning that the error callback will not be + * called for such responses. + * + * # Calling $http from outside AngularJS + * The `$http` service will not actually send the request until the next `$digest()` is + * executed. Normally this is not an issue, since almost all the time your call to `$http` will + * be from within a `$apply()` block. + * If you are calling `$http` from outside Angular, then you should wrap it in a call to + * `$apply` to cause a $digest to occur and also to handle errors in the block correctly. + * + * ``` + * $scope.$apply(function() { + * $http(...); + * }); + * ``` + * + * # Writing Unit Tests that use $http + * When unit testing you are mostly responsible for scheduling the `$digest` cycle. If you do + * not trigger a `$digest` before calling `$httpBackend.flush()` then the request will not have + * been made and `$httpBackend.expect(...)` expectations will fail. The solution is to run the + * code that calls the `$http()` method inside a $apply block as explained in the previous + * section. + * + * ``` + * $httpBackend.expectGET(...); + * $scope.$apply(function() { + * $http.get(...); + * }); + * $httpBackend.flush(); + * ``` + * + * # Shortcut methods + * + * Since all invocations of the $http service require passing in an HTTP method and URL, and + * POST/PUT requests require request data to be provided as well, shortcut methods + * were created: + * + *
+     *   $http.get('/someUrl').success(successCallback);
+     *   $http.post('/someUrl', data).success(successCallback);
+     * 
+ * + * Complete list of shortcut methods: + * + * - {@link ng.$http#methods_get $http.get} + * - {@link ng.$http#methods_head $http.head} + * - {@link ng.$http#methods_post $http.post} + * - {@link ng.$http#methods_put $http.put} + * - {@link ng.$http#methods_delete $http.delete} + * - {@link ng.$http#methods_jsonp $http.jsonp} + * + * + * # Setting HTTP Headers + * + * The $http service will automatically add certain HTTP headers to all requests. These defaults + * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration + * object, which currently contains this default configuration: + * + * - `$httpProvider.defaults.headers.common` (headers that are common for all requests): + * - `Accept: application/json, text/plain, * / *` + * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests) + * - `Content-Type: application/json` + * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests) + * - `Content-Type: application/json` + * + * To add or overwrite these defaults, simply add or remove a property from these configuration + * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object + * with the lowercased HTTP method name as the key, e.g. + * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }. + * + * The defaults can also be set at runtime via the `$http.defaults` object in the same + * fashion. In addition, you can supply a `headers` property in the config object passed when + * calling `$http(config)`, which overrides the defaults without changing them globally. + * + * + * # Transforming Requests and Responses + * + * Both requests and responses can be transformed using transform functions. By default, Angular + * applies these transformations: + * + * Request transformations: + * + * - If the `data` property of the request configuration object contains an object, serialize it + * into JSON format. + * + * Response transformations: + * + * - If XSRF prefix is detected, strip it (see Security Considerations section below). + * - If JSON response is detected, deserialize it using a JSON parser. + * + * To globally augment or override the default transforms, modify the + * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse` + * properties. These properties are by default an array of transform functions, which allows you + * to `push` or `unshift` a new transformation function into the transformation chain. You can + * also decide to completely override any default transformations by assigning your + * transformation functions to these properties directly without the array wrapper. + * + * Similarly, to locally override the request/response transforms, augment the + * `transformRequest` and/or `transformResponse` properties of the configuration object passed + * into `$http`. + * + * + * # Caching + * + * To enable caching, set the request configuration `cache` property to `true` (to use default + * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}). + * When the cache is enabled, `$http` stores the response from the server in the specified + * cache. The next time the same request is made, the response is served from the cache without + * sending a request to the server. + * + * Note that even if the response is served from cache, delivery of the data is asynchronous in + * the same way that real requests are. + * + * If there are multiple GET requests for the same URL that should be cached using the same + * cache, but the cache is not populated yet, only one request to the server will be made and + * the remaining requests will be fulfilled using the response from the first request. + * + * You can change the default cache to a new object (built with + * {@link ng.$cacheFactory `$cacheFactory`}) by updating the + * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set + * their `cache` property to `true` will now use this cache object. + * + * If you set the default cache to `false` then only requests that specify their own custom + * cache object will be cached. + * + * # Interceptors + * + * Before you start creating interceptors, be sure to understand the + * {@link ng.$q $q and deferred/promise APIs}. + * + * For purposes of global error handling, authentication, or any kind of synchronous or + * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be + * able to intercept requests before they are handed to the server and + * responses before they are handed over to the application code that + * initiated these requests. The interceptors leverage the {@link ng.$q + * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing. + * + * The interceptors are service factories that are registered with the `$httpProvider` by + * adding them to the `$httpProvider.interceptors` array. The factory is called and + * injected with dependencies (if specified) and returns the interceptor. + * + * There are two kinds of interceptors (and two kinds of rejection interceptors): + * + * * `request`: interceptors get called with http `config` object. The function is free to + * modify the `config` or create a new one. The function needs to return the `config` + * directly or as a promise. + * * `requestError`: interceptor gets called when a previous interceptor threw an error or + * resolved with a rejection. + * * `response`: interceptors get called with http `response` object. The function is free to + * modify the `response` or create a new one. The function needs to return the `response` + * directly or as a promise. + * * `responseError`: interceptor gets called when a previous interceptor threw an error or + * resolved with a rejection. + * + * + *
+     *   // register the interceptor as a service
+     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
+     *     return {
+     *       // optional method
+     *       'request': function(config) {
+     *         // do something on success
+     *         return config || $q.when(config);
+     *       },
+     *
+     *       // optional method
+     *      'requestError': function(rejection) {
+     *         // do something on error
+     *         if (canRecover(rejection)) {
+     *           return responseOrNewPromise
+     *         }
+     *         return $q.reject(rejection);
+     *       },
+     *
+     *
+     *
+     *       // optional method
+     *       'response': function(response) {
+     *         // do something on success
+     *         return response || $q.when(response);
+     *       },
+     *
+     *       // optional method
+     *      'responseError': function(rejection) {
+     *         // do something on error
+     *         if (canRecover(rejection)) {
+     *           return responseOrNewPromise
+     *         }
+     *         return $q.reject(rejection);
+     *       };
+     *     }
+     *   });
+     *
+     *   $httpProvider.interceptors.push('myHttpInterceptor');
+     *
+     *
+     *   // register the interceptor via an anonymous factory
+     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
+     *     return {
+     *      'request': function(config) {
+     *          // same as above
+     *       },
+     *       'response': function(response) {
+     *          // same as above
+     *       }
+     *     };
+     *   });
+     * 
+ * + * # Response interceptors (DEPRECATED) + * + * Before you start creating interceptors, be sure to understand the + * {@link ng.$q $q and deferred/promise APIs}. + * + * For purposes of global error handling, authentication or any kind of synchronous or + * asynchronous preprocessing of received responses, it is desirable to be able to intercept + * responses for http requests before they are handed over to the application code that + * initiated these requests. The response interceptors leverage the {@link ng.$q + * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing. + * + * The interceptors are service factories that are registered with the $httpProvider by + * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and + * injected with dependencies (if specified) and returns the interceptor — a function that + * takes a {@link ng.$q promise} and returns the original or a new promise. + * + *
+     *   // register the interceptor as a service
+     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
+     *     return function(promise) {
+     *       return promise.then(function(response) {
+     *         // do something on success
+     *         return response;
+     *       }, function(response) {
+     *         // do something on error
+     *         if (canRecover(response)) {
+     *           return responseOrNewPromise
+     *         }
+     *         return $q.reject(response);
+     *       });
+     *     }
+     *   });
+     *
+     *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
+     *
+     *
+     *   // register the interceptor via an anonymous factory
+     *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
+     *     return function(promise) {
+     *       // same as above
+     *     }
+     *   });
+     * 
+ * + * + * # Security Considerations + * + * When designing web applications, consider security threats from: + * + * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx + * JSON vulnerability} + * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} + * + * Both server and the client must cooperate in order to eliminate these threats. Angular comes + * pre-configured with strategies that address these issues, but for this to work backend server + * cooperation is required. + * + * ## JSON Vulnerability Protection + * + * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx + * JSON vulnerability} allows third party website to turn your JSON resource URL into + * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To + * counter this your server can prefix all JSON requests with following string `")]}',\n"`. + * Angular will automatically strip the prefix before processing it as JSON. + * + * For example if your server needs to return: + *
+     * ['one','two']
+     * 
+ * + * which is vulnerable to attack, your server can return: + *
+     * )]}',
+     * ['one','two']
+     * 
+ * + * Angular will strip the prefix, before processing the JSON. + * + * + * ## Cross Site Request Forgery (XSRF) Protection + * + * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which + * an unauthorized site can gain your user's private data. Angular provides a mechanism + * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie + * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only + * JavaScript that runs on your domain could read the cookie, your server can be assured that + * the XHR came from JavaScript running on your domain. The header will not be set for + * cross-domain requests. + * + * To take advantage of this, your server needs to set a token in a JavaScript readable session + * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the + * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure + * that only JavaScript running on your domain could have sent the request. The token must be + * unique for each user and must be verifiable by the server (to prevent the JavaScript from + * making up its own tokens). We recommend that the token is a digest of your site's + * authentication cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} + * for added security. + * + * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName + * properties of either $httpProvider.defaults, or the per-request config object. + * + * + * @param {object} config Object describing the request to be made and how it should be + * processed. The object has following properties: + * + * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc) + * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested. + * - **params** – `{Object.}` – Map of strings or objects which will be turned + * to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be + * JSONified. + * - **data** – `{string|Object}` – Data to be sent as the request message data. + * - **headers** – `{Object}` – Map of strings or functions which return strings representing + * HTTP headers to send to the server. If the return value of a function is null, the + * header will not be sent. + * - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token. + * - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token. + * - **transformRequest** – + * `{function(data, headersGetter)|Array.}` – + * transform function or an array of such functions. The transform function takes the http + * request body and headers and returns its transformed (typically serialized) version. + * - **transformResponse** – + * `{function(data, headersGetter)|Array.}` – + * transform function or an array of such functions. The transform function takes the http + * response body and headers and returns its transformed (typically deserialized) version. + * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the + * GET request, otherwise if a cache instance built with + * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for + * caching. + * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} + * that should abort the request when resolved. + * - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the + * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5 + * requests with credentials} for more information. + * - **responseType** - `{string}` - see {@link + * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}. + * + * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the + * standard `then` method and two http specific methods: `success` and `error`. The `then` + * method takes two arguments a success and an error callback which will be called with a + * response object. The `success` and `error` methods take a single argument - a function that + * will be called when the request succeeds or fails respectively. The arguments passed into + * these functions are destructured representation of the response object passed into the + * `then` method. The response object has these properties: + * + * - **data** – `{string|Object}` – The response body transformed with the transform + * functions. + * - **status** – `{number}` – HTTP status code of the response. + * - **headers** – `{function([headerName])}` – Header getter function. + * - **config** – `{Object}` – The configuration object that was used to generate the request. + * + * @property {Array.} pendingRequests Array of config objects for currently pending + * requests. This is primarily meant to be used for debugging purposes. + * + * + * @example + + +
+ + +
+ + + +
http status code: {{status}}
+
http response data: {{data}}
+
+
+ + function FetchCtrl($scope, $http, $templateCache) { + $scope.method = 'GET'; + $scope.url = 'http-hello.html'; + + $scope.fetch = function() { + $scope.code = null; + $scope.response = null; + + $http({method: $scope.method, url: $scope.url, cache: $templateCache}). + success(function(data, status) { + $scope.status = status; + $scope.data = data; + }). + error(function(data, status) { + $scope.data = data || "Request failed"; + $scope.status = status; + }); + }; + + $scope.updateModel = function(method, url) { + $scope.method = method; + $scope.url = url; + }; + } + + + Hello, $http! + + + it('should make an xhr GET request', function() { + element(':button:contains("Sample GET")').click(); + element(':button:contains("fetch")').click(); + expect(binding('status')).toBe('200'); + expect(binding('data')).toMatch(/Hello, \$http!/); + }); + + it('should make a JSONP request to angularjs.org', function() { + element(':button:contains("Sample JSONP")').click(); + element(':button:contains("fetch")').click(); + expect(binding('status')).toBe('200'); + expect(binding('data')).toMatch(/Super Hero!/); + }); + + it('should make JSONP request to invalid URL and invoke the error handler', + function() { + element(':button:contains("Invalid JSONP")').click(); + element(':button:contains("fetch")').click(); + expect(binding('status')).toBe('0'); + expect(binding('data')).toBe('Request failed'); + }); + +
+ */ + function $http(requestConfig) { + var config = { + transformRequest: defaults.transformRequest, + transformResponse: defaults.transformResponse + }; + var headers = mergeHeaders(requestConfig); + + extend(config, requestConfig); + config.headers = headers; + config.method = uppercase(config.method); + + var xsrfValue = urlIsSameOrigin(config.url) + ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName] + : undefined; + if (xsrfValue) { + headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue; + } + + + var serverRequest = function(config) { + headers = config.headers; + var reqData = transformData(config.data, headersGetter(headers), config.transformRequest); + + // strip content-type if data is undefined + if (isUndefined(config.data)) { + forEach(headers, function(value, header) { + if (lowercase(header) === 'content-type') { + delete headers[header]; + } + }); + } + + if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) { + config.withCredentials = defaults.withCredentials; + } + + // send request + return sendReq(config, reqData, headers).then(transformResponse, transformResponse); + }; + + var chain = [serverRequest, undefined]; + var promise = $q.when(config); + + // apply interceptors + forEach(reversedInterceptors, function(interceptor) { + if (interceptor.request || interceptor.requestError) { + chain.unshift(interceptor.request, interceptor.requestError); + } + if (interceptor.response || interceptor.responseError) { + chain.push(interceptor.response, interceptor.responseError); + } + }); + + while(chain.length) { + var thenFn = chain.shift(); + var rejectFn = chain.shift(); + + promise = promise.then(thenFn, rejectFn); + } + + promise.success = function(fn) { + promise.then(function(response) { + fn(response.data, response.status, response.headers, config); + }); + return promise; + }; + + promise.error = function(fn) { + promise.then(null, function(response) { + fn(response.data, response.status, response.headers, config); + }); + return promise; + }; + + return promise; + + function transformResponse(response) { + // make a copy since the response must be cacheable + var resp = extend({}, response, { + data: transformData(response.data, response.headers, config.transformResponse) + }); + return (isSuccess(response.status)) + ? resp + : $q.reject(resp); + } + + function mergeHeaders(config) { + var defHeaders = defaults.headers, + reqHeaders = extend({}, config.headers), + defHeaderName, lowercaseDefHeaderName, reqHeaderName; + + defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]); + + // execute if header value is function + execHeaders(defHeaders); + execHeaders(reqHeaders); + + // using for-in instead of forEach to avoid unecessary iteration after header has been found + defaultHeadersIteration: + for (defHeaderName in defHeaders) { + lowercaseDefHeaderName = lowercase(defHeaderName); + + for (reqHeaderName in reqHeaders) { + if (lowercase(reqHeaderName) === lowercaseDefHeaderName) { + continue defaultHeadersIteration; + } + } + + reqHeaders[defHeaderName] = defHeaders[defHeaderName]; + } + + return reqHeaders; + + function execHeaders(headers) { + var headerContent; + + forEach(headers, function(headerFn, header) { + if (isFunction(headerFn)) { + headerContent = headerFn(); + if (headerContent != null) { + headers[header] = headerContent; + } else { + delete headers[header]; + } + } + }); + } + } + } + + $http.pendingRequests = []; + + /** + * @ngdoc method + * @name ng.$http#get + * @methodOf ng.$http + * + * @description + * Shortcut method to perform `GET` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name ng.$http#delete + * @methodOf ng.$http + * + * @description + * Shortcut method to perform `DELETE` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name ng.$http#head + * @methodOf ng.$http + * + * @description + * Shortcut method to perform `HEAD` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name ng.$http#jsonp + * @methodOf ng.$http + * + * @description + * Shortcut method to perform `JSONP` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request. + * Should contain `JSON_CALLBACK` string. + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + createShortMethods('get', 'delete', 'head', 'jsonp'); + + /** + * @ngdoc method + * @name ng.$http#post + * @methodOf ng.$http + * + * @description + * Shortcut method to perform `POST` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {*} data Request content + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name ng.$http#put + * @methodOf ng.$http + * + * @description + * Shortcut method to perform `PUT` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {*} data Request content + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + createShortMethodsWithData('post', 'put'); + + /** + * @ngdoc property + * @name ng.$http#defaults + * @propertyOf ng.$http + * + * @description + * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of + * default headers, withCredentials as well as request and response transformations. + * + * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above. + */ + $http.defaults = defaults; + + + return $http; + + + function createShortMethods(names) { + forEach(arguments, function(name) { + $http[name] = function(url, config) { + return $http(extend(config || {}, { + method: name, + url: url + })); + }; + }); + } + + + function createShortMethodsWithData(name) { + forEach(arguments, function(name) { + $http[name] = function(url, data, config) { + return $http(extend(config || {}, { + method: name, + url: url, + data: data + })); + }; + }); + } + + + /** + * Makes the request. + * + * !!! ACCESSES CLOSURE VARS: + * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests + */ + function sendReq(config, reqData, reqHeaders) { + var deferred = $q.defer(), + promise = deferred.promise, + cache, + cachedResp, + url = buildUrl(config.url, config.params); + + $http.pendingRequests.push(config); + promise.then(removePendingReq, removePendingReq); + + + if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') { + cache = isObject(config.cache) ? config.cache + : isObject(defaults.cache) ? defaults.cache + : defaultCache; + } + + if (cache) { + cachedResp = cache.get(url); + if (isDefined(cachedResp)) { + if (cachedResp.then) { + // cached request has already been sent, but there is no response yet + cachedResp.then(removePendingReq, removePendingReq); + return cachedResp; + } else { + // serving from cache + if (isArray(cachedResp)) { + resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2])); + } else { + resolvePromise(cachedResp, 200, {}); + } + } + } else { + // put the promise for the non-transformed response into cache as a placeholder + cache.put(url, promise); + } + } + + // if we won't have the response in cache, send the request to the backend + if (isUndefined(cachedResp)) { + $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout, + config.withCredentials, config.responseType); + } + + return promise; + + + /** + * Callback registered to $httpBackend(): + * - caches the response if desired + * - resolves the raw $http promise + * - calls $apply + */ + function done(status, response, headersString) { + if (cache) { + if (isSuccess(status)) { + cache.put(url, [status, response, parseHeaders(headersString)]); + } else { + // remove promise from the cache + cache.remove(url); + } + } + + resolvePromise(response, status, headersString); + if (!$rootScope.$$phase) $rootScope.$apply(); + } + + + /** + * Resolves the raw $http promise. + */ + function resolvePromise(response, status, headers) { + // normalize internal statuses to 0 + status = Math.max(status, 0); + + (isSuccess(status) ? deferred.resolve : deferred.reject)({ + data: response, + status: status, + headers: headersGetter(headers), + config: config + }); + } + + + function removePendingReq() { + var idx = indexOf($http.pendingRequests, config); + if (idx !== -1) $http.pendingRequests.splice(idx, 1); + } + } + + + function buildUrl(url, params) { + if (!params) return url; + var parts = []; + forEachSorted(params, function(value, key) { + if (value === null || isUndefined(value)) return; + if (!isArray(value)) value = [value]; + + forEach(value, function(v) { + if (isObject(v)) { + v = toJson(v); + } + parts.push(encodeUriQuery(key) + '=' + + encodeUriQuery(v)); + }); + }); + return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&'); + } + + + }]; +} + +var XHR = window.XMLHttpRequest || function() { + /* global ActiveXObject */ + try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {} + try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {} + try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {} + throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest."); +}; + + +/** + * @ngdoc object + * @name ng.$httpBackend + * @requires $browser + * @requires $window + * @requires $document + * + * @description + * HTTP backend used by the {@link ng.$http service} that delegates to + * XMLHttpRequest object or JSONP and deals with browser incompatibilities. + * + * You should never need to use this service directly, instead use the higher-level abstractions: + * {@link ng.$http $http} or {@link ngResource.$resource $resource}. + * + * During testing this implementation is swapped with {@link ngMock.$httpBackend mock + * $httpBackend} which can be trained with responses. + */ +function $HttpBackendProvider() { + this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) { + return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, $document[0]); + }]; +} + +function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument) { + var ABORTED = -1; + + // TODO(vojta): fix the signature + return function(method, url, post, callback, headers, timeout, withCredentials, responseType) { + var status; + $browser.$$incOutstandingRequestCount(); + url = url || $browser.url(); + + if (lowercase(method) == 'jsonp') { + var callbackId = '_' + (callbacks.counter++).toString(36); + callbacks[callbackId] = function(data) { + callbacks[callbackId].data = data; + }; + + var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId), + function() { + if (callbacks[callbackId].data) { + completeRequest(callback, 200, callbacks[callbackId].data); + } else { + completeRequest(callback, status || -2); + } + delete callbacks[callbackId]; + }); + } else { + var xhr = new XHR(); + xhr.open(method, url, true); + forEach(headers, function(value, key) { + if (isDefined(value)) { + xhr.setRequestHeader(key, value); + } + }); + + // In IE6 and 7, this might be called synchronously when xhr.send below is called and the + // response is in the cache. the promise api will ensure that to the app code the api is + // always async + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + var responseHeaders = null, + response = null; + + if(status !== ABORTED) { + responseHeaders = xhr.getAllResponseHeaders(); + response = xhr.responseType ? xhr.response : xhr.responseText; + } + + // responseText is the old-school way of retrieving response (supported by IE8 & 9) + // response/responseType properties were introduced in XHR Level2 spec (supported by IE10) + completeRequest(callback, + status || xhr.status, + response, + responseHeaders); + } + }; + + if (withCredentials) { + xhr.withCredentials = true; + } + + if (responseType) { + xhr.responseType = responseType; + } + + xhr.send(post || null); + } + + if (timeout > 0) { + var timeoutId = $browserDefer(timeoutRequest, timeout); + } else if (timeout && timeout.then) { + timeout.then(timeoutRequest); + } + + + function timeoutRequest() { + status = ABORTED; + jsonpDone && jsonpDone(); + xhr && xhr.abort(); + } + + function completeRequest(callback, status, response, headersString) { + var protocol = urlResolve(url).protocol; + + // cancel timeout and subsequent timeout promise resolution + timeoutId && $browserDefer.cancel(timeoutId); + jsonpDone = xhr = null; + + // fix status code for file protocol (it's always 0) + status = (protocol == 'file' && status === 0) ? (response ? 200 : 404) : status; + + // normalize IE bug (http://bugs.jquery.com/ticket/1450) + status = status == 1223 ? 204 : status; + + callback(status, response, headersString); + $browser.$$completeOutstandingRequest(noop); + } + }; + + function jsonpReq(url, done) { + // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.: + // - fetches local scripts via XHR and evals them + // - adds and immediately removes script elements from the document + var script = rawDocument.createElement('script'), + doneWrapper = function() { + script.onreadystatechange = script.onload = script.onerror = null; + rawDocument.body.removeChild(script); + if (done) done(); + }; + + script.type = 'text/javascript'; + script.src = url; + + if (msie && msie <= 8) { + script.onreadystatechange = function() { + if (/loaded|complete/.test(script.readyState)) { + doneWrapper(); + } + }; + } else { + script.onload = script.onerror = function() { + doneWrapper(); + }; + } + + rawDocument.body.appendChild(script); + return doneWrapper; + } +} + +var $interpolateMinErr = minErr('$interpolate'); + +/** + * @ngdoc object + * @name ng.$interpolateProvider + * @function + * + * @description + * + * Used for configuring the interpolation markup. Defaults to `{{` and `}}`. + * + * @example + + + +
+ //demo.label// +
+
+ + it('should interpolate binding with custom symbols', function() { + expect(binding('demo.label')).toBe('This binding is brought you by // interpolation symbols.'); + }); + +
+ */ +function $InterpolateProvider() { + var startSymbol = '{{'; + var endSymbol = '}}'; + + /** + * @ngdoc method + * @name ng.$interpolateProvider#startSymbol + * @methodOf ng.$interpolateProvider + * @description + * Symbol to denote start of expression in the interpolated string. Defaults to `{{`. + * + * @param {string=} value new value to set the starting symbol to. + * @returns {string|self} Returns the symbol when used as getter and self if used as setter. + */ + this.startSymbol = function(value){ + if (value) { + startSymbol = value; + return this; + } else { + return startSymbol; + } + }; + + /** + * @ngdoc method + * @name ng.$interpolateProvider#endSymbol + * @methodOf ng.$interpolateProvider + * @description + * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`. + * + * @param {string=} value new value to set the ending symbol to. + * @returns {string|self} Returns the symbol when used as getter and self if used as setter. + */ + this.endSymbol = function(value){ + if (value) { + endSymbol = value; + return this; + } else { + return endSymbol; + } + }; + + + this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) { + var startSymbolLength = startSymbol.length, + endSymbolLength = endSymbol.length; + + /** + * @ngdoc function + * @name ng.$interpolate + * @function + * + * @requires $parse + * @requires $sce + * + * @description + * + * Compiles a string with markup into an interpolation function. This service is used by the + * HTML {@link ng.$compile $compile} service for data binding. See + * {@link ng.$interpolateProvider $interpolateProvider} for configuring the + * interpolation markup. + * + * +
+         var $interpolate = ...; // injected
+         var exp = $interpolate('Hello {{name}}!');
+         expect(exp({name:'Angular'}).toEqual('Hello Angular!');
+       
+ * + * + * @param {string} text The text with markup to interpolate. + * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have + * embedded expression in order to return an interpolation function. Strings with no + * embedded expression will return null for the interpolation function. + * @param {string=} trustedContext when provided, the returned function passes the interpolated + * result through {@link ng.$sce#methods_getTrusted $sce.getTrusted(interpolatedResult, + * trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that + * provides Strict Contextual Escaping for details. + * @returns {function(context)} an interpolation function which is used to compute the + * interpolated string. The function has these parameters: + * + * * `context`: an object against which any expressions embedded in the strings are evaluated + * against. + * + */ + function $interpolate(text, mustHaveExpression, trustedContext) { + var startIndex, + endIndex, + index = 0, + parts = [], + length = text.length, + hasInterpolation = false, + fn, + exp, + concat = []; + + while(index < length) { + if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) && + ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) { + (index != startIndex) && parts.push(text.substring(index, startIndex)); + parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex))); + fn.exp = exp; + index = endIndex + endSymbolLength; + hasInterpolation = true; + } else { + // we did not find anything, so we have to add the remainder to the parts array + (index != length) && parts.push(text.substring(index)); + index = length; + } + } + + if (!(length = parts.length)) { + // we added, nothing, must have been an empty string. + parts.push(''); + length = 1; + } + + // Concatenating expressions makes it hard to reason about whether some combination of + // concatenated values are unsafe to use and could easily lead to XSS. By requiring that a + // single expression be used for iframe[src], object[src], etc., we ensure that the value + // that's used is assigned or constructed by some JS code somewhere that is more testable or + // make it obvious that you bound the value to some user controlled value. This helps reduce + // the load when auditing for XSS issues. + if (trustedContext && parts.length > 1) { + throw $interpolateMinErr('noconcat', + "Error while interpolating: {0}\nStrict Contextual Escaping disallows " + + "interpolations that concatenate multiple expressions when a trusted value is " + + "required. See http://docs.angularjs.org/api/ng.$sce", text); + } + + if (!mustHaveExpression || hasInterpolation) { + concat.length = length; + fn = function(context) { + try { + for(var i = 0, ii = length, part; i 0 && iteration >= count) { + deferred.resolve(iteration); + clearInterval(promise.$$intervalId); + delete intervals[promise.$$intervalId]; + } + + if (!skipApply) $rootScope.$apply(); + + }, delay); + + intervals[promise.$$intervalId] = deferred; + + return promise; + } + + + /** + * @ngdoc function + * @name ng.$interval#cancel + * @methodOf ng.$interval + * + * @description + * Cancels a task associated with the `promise`. + * + * @param {number} promise Promise returned by the `$interval` function. + * @returns {boolean} Returns `true` if the task was successfully canceled. + */ + interval.cancel = function(promise) { + if (promise && promise.$$intervalId in intervals) { + intervals[promise.$$intervalId].reject('canceled'); + clearInterval(promise.$$intervalId); + delete intervals[promise.$$intervalId]; + return true; + } + return false; + }; + + return interval; + }]; +} + +/** + * @ngdoc object + * @name ng.$locale + * + * @description + * $locale service provides localization rules for various Angular components. As of right now the + * only public api is: + * + * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`) + */ +function $LocaleProvider(){ + this.$get = function() { + return { + id: 'en-us', + + NUMBER_FORMATS: { + DECIMAL_SEP: '.', + GROUP_SEP: ',', + PATTERNS: [ + { // Decimal Pattern + minInt: 1, + minFrac: 0, + maxFrac: 3, + posPre: '', + posSuf: '', + negPre: '-', + negSuf: '', + gSize: 3, + lgSize: 3 + },{ //Currency Pattern + minInt: 1, + minFrac: 2, + maxFrac: 2, + posPre: '\u00A4', + posSuf: '', + negPre: '(\u00A4', + negSuf: ')', + gSize: 3, + lgSize: 3 + } + ], + CURRENCY_SYM: '$' + }, + + DATETIME_FORMATS: { + MONTH: + 'January,February,March,April,May,June,July,August,September,October,November,December' + .split(','), + SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','), + DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','), + SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','), + AMPMS: ['AM','PM'], + medium: 'MMM d, y h:mm:ss a', + short: 'M/d/yy h:mm a', + fullDate: 'EEEE, MMMM d, y', + longDate: 'MMMM d, y', + mediumDate: 'MMM d, y', + shortDate: 'M/d/yy', + mediumTime: 'h:mm:ss a', + shortTime: 'h:mm a' + }, + + pluralCat: function(num) { + if (num === 1) { + return 'one'; + } + return 'other'; + } + }; + }; +} + +var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/, + DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21}; +var $locationMinErr = minErr('$location'); + + +/** + * Encode path using encodeUriSegment, ignoring forward slashes + * + * @param {string} path Path to encode + * @returns {string} + */ +function encodePath(path) { + var segments = path.split('/'), + i = segments.length; + + while (i--) { + segments[i] = encodeUriSegment(segments[i]); + } + + return segments.join('/'); +} + +function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) { + var parsedUrl = urlResolve(absoluteUrl, appBase); + + locationObj.$$protocol = parsedUrl.protocol; + locationObj.$$host = parsedUrl.hostname; + locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null; +} + + +function parseAppUrl(relativeUrl, locationObj, appBase) { + var prefixed = (relativeUrl.charAt(0) !== '/'); + if (prefixed) { + relativeUrl = '/' + relativeUrl; + } + var match = urlResolve(relativeUrl, appBase); + locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? + match.pathname.substring(1) : match.pathname); + locationObj.$$search = parseKeyValue(match.search); + locationObj.$$hash = decodeURIComponent(match.hash); + + // make sure path starts with '/'; + if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') { + locationObj.$$path = '/' + locationObj.$$path; + } +} + + +/** + * + * @param {string} begin + * @param {string} whole + * @returns {string} returns text from whole after begin or undefined if it does not begin with + * expected string. + */ +function beginsWith(begin, whole) { + if (whole.indexOf(begin) === 0) { + return whole.substr(begin.length); + } +} + + +function stripHash(url) { + var index = url.indexOf('#'); + return index == -1 ? url : url.substr(0, index); +} + + +function stripFile(url) { + return url.substr(0, stripHash(url).lastIndexOf('/') + 1); +} + +/* return the server only (scheme://host:port) */ +function serverBase(url) { + return url.substring(0, url.indexOf('/', url.indexOf('//') + 2)); +} + + +/** + * LocationHtml5Url represents an url + * This object is exposed as $location service when HTML5 mode is enabled and supported + * + * @constructor + * @param {string} appBase application base URL + * @param {string} basePrefix url path prefix + */ +function LocationHtml5Url(appBase, basePrefix) { + this.$$html5 = true; + basePrefix = basePrefix || ''; + var appBaseNoFile = stripFile(appBase); + parseAbsoluteUrl(appBase, this, appBase); + + + /** + * Parse given html5 (regular) url string into properties + * @param {string} newAbsoluteUrl HTML5 url + * @private + */ + this.$$parse = function(url) { + var pathUrl = beginsWith(appBaseNoFile, url); + if (!isString(pathUrl)) { + throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url, + appBaseNoFile); + } + + parseAppUrl(pathUrl, this, appBase); + + if (!this.$$path) { + this.$$path = '/'; + } + + this.$$compose(); + }; + + /** + * Compose url and update `absUrl` property + * @private + */ + this.$$compose = function() { + var search = toKeyValue(this.$$search), + hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; + + this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; + this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/' + }; + + this.$$rewrite = function(url) { + var appUrl, prevAppUrl; + + if ( (appUrl = beginsWith(appBase, url)) !== undefined ) { + prevAppUrl = appUrl; + if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) { + return appBaseNoFile + (beginsWith('/', appUrl) || appUrl); + } else { + return appBase + prevAppUrl; + } + } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) { + return appBaseNoFile + appUrl; + } else if (appBaseNoFile == url + '/') { + return appBaseNoFile; + } + }; +} + + +/** + * LocationHashbangUrl represents url + * This object is exposed as $location service when developer doesn't opt into html5 mode. + * It also serves as the base class for html5 mode fallback on legacy browsers. + * + * @constructor + * @param {string} appBase application base URL + * @param {string} hashPrefix hashbang prefix + */ +function LocationHashbangUrl(appBase, hashPrefix) { + var appBaseNoFile = stripFile(appBase); + + parseAbsoluteUrl(appBase, this, appBase); + + + /** + * Parse given hashbang url into properties + * @param {string} url Hashbang url + * @private + */ + this.$$parse = function(url) { + var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url); + var withoutHashUrl = withoutBaseUrl.charAt(0) == '#' + ? beginsWith(hashPrefix, withoutBaseUrl) + : (this.$$html5) + ? withoutBaseUrl + : ''; + + if (!isString(withoutHashUrl)) { + throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url, + hashPrefix); + } + parseAppUrl(withoutHashUrl, this, appBase); + + this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); + + this.$$compose(); + + /* + * In Windows, on an anchor node on documents loaded from + * the filesystem, the browser will return a pathname + * prefixed with the drive name ('/C:/path') when a + * pathname without a drive is set: + * * a.setAttribute('href', '/foo') + * * a.pathname === '/C:/foo' //true + * + * Inside of Angular, we're always using pathnames that + * do not include drive names for routing. + */ + function removeWindowsDriveName (path, url, base) { + /* + Matches paths for file protocol on windows, + such as /C:/foo/bar, and captures only /foo/bar. + */ + var windowsFilePathExp = /^\/?.*?:(\/.*)/; + + var firstPathSegmentMatch; + + //Get the relative path from the input URL. + if (url.indexOf(base) === 0) { + url = url.replace(base, ''); + } + + /* + * The input URL intentionally contains a + * first path segment that ends with a colon. + */ + if (windowsFilePathExp.exec(url)) { + return path; + } + + firstPathSegmentMatch = windowsFilePathExp.exec(path); + return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path; + } + }; + + /** + * Compose hashbang url and update `absUrl` property + * @private + */ + this.$$compose = function() { + var search = toKeyValue(this.$$search), + hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; + + this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; + this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : ''); + }; + + this.$$rewrite = function(url) { + if(stripHash(appBase) == stripHash(url)) { + return url; + } + }; +} + + +/** + * LocationHashbangUrl represents url + * This object is exposed as $location service when html5 history api is enabled but the browser + * does not support it. + * + * @constructor + * @param {string} appBase application base URL + * @param {string} hashPrefix hashbang prefix + */ +function LocationHashbangInHtml5Url(appBase, hashPrefix) { + this.$$html5 = true; + LocationHashbangUrl.apply(this, arguments); + + var appBaseNoFile = stripFile(appBase); + + this.$$rewrite = function(url) { + var appUrl; + + if ( appBase == stripHash(url) ) { + return url; + } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) { + return appBase + hashPrefix + appUrl; + } else if ( appBaseNoFile === url + '/') { + return appBaseNoFile; + } + }; +} + + +LocationHashbangInHtml5Url.prototype = + LocationHashbangUrl.prototype = + LocationHtml5Url.prototype = { + + /** + * Are we in html5 mode? + * @private + */ + $$html5: false, + + /** + * Has any change been replacing ? + * @private + */ + $$replace: false, + + /** + * @ngdoc method + * @name ng.$location#absUrl + * @methodOf ng.$location + * + * @description + * This method is getter only. + * + * Return full url representation with all segments encoded according to rules specified in + * {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}. + * + * @return {string} full url + */ + absUrl: locationGetter('$$absUrl'), + + /** + * @ngdoc method + * @name ng.$location#url + * @methodOf ng.$location + * + * @description + * This method is getter / setter. + * + * Return url (e.g. `/path?a=b#hash`) when called without any parameter. + * + * Change path, search and hash, when called with parameter and return `$location`. + * + * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`) + * @param {string=} replace The path that will be changed + * @return {string} url + */ + url: function(url, replace) { + if (isUndefined(url)) + return this.$$url; + + var match = PATH_MATCH.exec(url); + if (match[1]) this.path(decodeURIComponent(match[1])); + if (match[2] || match[1]) this.search(match[3] || ''); + this.hash(match[5] || '', replace); + + return this; + }, + + /** + * @ngdoc method + * @name ng.$location#protocol + * @methodOf ng.$location + * + * @description + * This method is getter only. + * + * Return protocol of current url. + * + * @return {string} protocol of current url + */ + protocol: locationGetter('$$protocol'), + + /** + * @ngdoc method + * @name ng.$location#host + * @methodOf ng.$location + * + * @description + * This method is getter only. + * + * Return host of current url. + * + * @return {string} host of current url. + */ + host: locationGetter('$$host'), + + /** + * @ngdoc method + * @name ng.$location#port + * @methodOf ng.$location + * + * @description + * This method is getter only. + * + * Return port of current url. + * + * @return {Number} port + */ + port: locationGetter('$$port'), + + /** + * @ngdoc method + * @name ng.$location#path + * @methodOf ng.$location + * + * @description + * This method is getter / setter. + * + * Return path of current url when called without any parameter. + * + * Change path when called with parameter and return `$location`. + * + * Note: Path should always begin with forward slash (/), this method will add the forward slash + * if it is missing. + * + * @param {string=} path New path + * @return {string} path + */ + path: locationGetterSetter('$$path', function(path) { + return path.charAt(0) == '/' ? path : '/' + path; + }), + + /** + * @ngdoc method + * @name ng.$location#search + * @methodOf ng.$location + * + * @description + * This method is getter / setter. + * + * Return search part (as object) of current url when called without any parameter. + * + * Change search part when called with parameter and return `$location`. + * + * @param {string|Object.|Object.>} search New search params - string or + * hash object. Hash object may contain an array of values, which will be decoded as duplicates in + * the url. + * + * @param {(string|Array)=} paramValue If `search` is a string, then `paramValue` will override only a + * single search parameter. If `paramValue` is an array, it will set the parameter as a + * comma-separated value. If `paramValue` is `null`, the parameter will be deleted. + * + * @return {string} search + */ + search: function(search, paramValue) { + switch (arguments.length) { + case 0: + return this.$$search; + case 1: + if (isString(search)) { + this.$$search = parseKeyValue(search); + } else if (isObject(search)) { + this.$$search = search; + } else { + throw $locationMinErr('isrcharg', + 'The first argument of the `$location#search()` call must be a string or an object.'); + } + break; + default: + if (isUndefined(paramValue) || paramValue === null) { + delete this.$$search[search]; + } else { + this.$$search[search] = paramValue; + } + } + + this.$$compose(); + return this; + }, + + /** + * @ngdoc method + * @name ng.$location#hash + * @methodOf ng.$location + * + * @description + * This method is getter / setter. + * + * Return hash fragment when called without any parameter. + * + * Change hash fragment when called with parameter and return `$location`. + * + * @param {string=} hash New hash fragment + * @return {string} hash + */ + hash: locationGetterSetter('$$hash', identity), + + /** + * @ngdoc method + * @name ng.$location#replace + * @methodOf ng.$location + * + * @description + * If called, all changes to $location during current `$digest` will be replacing current history + * record, instead of adding new one. + */ + replace: function() { + this.$$replace = true; + return this; + } +}; + +function locationGetter(property) { + return function() { + return this[property]; + }; +} + + +function locationGetterSetter(property, preprocess) { + return function(value) { + if (isUndefined(value)) + return this[property]; + + this[property] = preprocess(value); + this.$$compose(); + + return this; + }; +} + + +/** + * @ngdoc object + * @name ng.$location + * + * @requires $browser + * @requires $sniffer + * @requires $rootElement + * + * @description + * The $location service parses the URL in the browser address bar (based on the + * {@link https://developer.mozilla.org/en/window.location window.location}) and makes the URL + * available to your application. Changes to the URL in the address bar are reflected into + * $location service and changes to $location are reflected into the browser address bar. + * + * **The $location service:** + * + * - Exposes the current URL in the browser address bar, so you can + * - Watch and observe the URL. + * - Change the URL. + * - Synchronizes the URL with the browser when the user + * - Changes the address bar. + * - Clicks the back or forward button (or clicks a History link). + * - Clicks on a link. + * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash). + * + * For more information see {@link guide/dev_guide.services.$location Developer Guide: Angular + * Services: Using $location} + */ + +/** + * @ngdoc object + * @name ng.$locationProvider + * @description + * Use the `$locationProvider` to configure how the application deep linking paths are stored. + */ +function $LocationProvider(){ + var hashPrefix = '', + html5Mode = false; + + /** + * @ngdoc property + * @name ng.$locationProvider#hashPrefix + * @methodOf ng.$locationProvider + * @description + * @param {string=} prefix Prefix for hash part (containing path and search) + * @returns {*} current value if used as getter or itself (chaining) if used as setter + */ + this.hashPrefix = function(prefix) { + if (isDefined(prefix)) { + hashPrefix = prefix; + return this; + } else { + return hashPrefix; + } + }; + + /** + * @ngdoc property + * @name ng.$locationProvider#html5Mode + * @methodOf ng.$locationProvider + * @description + * @param {boolean=} mode Use HTML5 strategy if available. + * @returns {*} current value if used as getter or itself (chaining) if used as setter + */ + this.html5Mode = function(mode) { + if (isDefined(mode)) { + html5Mode = mode; + return this; + } else { + return html5Mode; + } + }; + + /** + * @ngdoc event + * @name ng.$location#$locationChangeStart + * @eventOf ng.$location + * @eventType broadcast on root scope + * @description + * Broadcasted before a URL will change. This change can be prevented by calling + * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more + * details about event object. Upon successful change + * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired. + * + * @param {Object} angularEvent Synthetic event object. + * @param {string} newUrl New URL + * @param {string=} oldUrl URL that was before it was changed. + */ + + /** + * @ngdoc event + * @name ng.$location#$locationChangeSuccess + * @eventOf ng.$location + * @eventType broadcast on root scope + * @description + * Broadcasted after a URL was changed. + * + * @param {Object} angularEvent Synthetic event object. + * @param {string} newUrl New URL + * @param {string=} oldUrl URL that was before it was changed. + */ + + this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', + function( $rootScope, $browser, $sniffer, $rootElement) { + var $location, + LocationMode, + baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to '' + initialUrl = $browser.url(), + appBase; + + if (html5Mode) { + appBase = serverBase(initialUrl) + (baseHref || '/'); + LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url; + } else { + appBase = stripHash(initialUrl); + LocationMode = LocationHashbangUrl; + } + $location = new LocationMode(appBase, '#' + hashPrefix); + $location.$$parse($location.$$rewrite(initialUrl)); + + $rootElement.on('click', function(event) { + // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser) + // currently we open nice url link and redirect then + + if (event.ctrlKey || event.metaKey || event.which == 2) return; + + var elm = jqLite(event.target); + + // traverse the DOM up to find first A tag + while (lowercase(elm[0].nodeName) !== 'a') { + // ignore rewriting if no A tag (reached root element, or no parent - removed from document) + if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return; + } + + var absHref = elm.prop('href'); + var rewrittenUrl = $location.$$rewrite(absHref); + + if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) { + event.preventDefault(); + if (rewrittenUrl != $browser.url()) { + // update location manually + $location.$$parse(rewrittenUrl); + $rootScope.$apply(); + // hack to work around FF6 bug 684208 when scenario runner clicks on links + window.angular['ff-684208-preventDefault'] = true; + } + } + }); + + + // rewrite hashbang url <> html5 url + if ($location.absUrl() != initialUrl) { + $browser.url($location.absUrl(), true); + } + + // update $location when $browser url changes + $browser.onUrlChange(function(newUrl) { + if ($location.absUrl() != newUrl) { + if ($rootScope.$broadcast('$locationChangeStart', newUrl, + $location.absUrl()).defaultPrevented) { + $browser.url($location.absUrl()); + return; + } + $rootScope.$evalAsync(function() { + var oldUrl = $location.absUrl(); + + $location.$$parse(newUrl); + afterLocationChange(oldUrl); + }); + if (!$rootScope.$$phase) $rootScope.$digest(); + } + }); + + // update browser + var changeCounter = 0; + $rootScope.$watch(function $locationWatch() { + var oldUrl = $browser.url(); + var currentReplace = $location.$$replace; + + if (!changeCounter || oldUrl != $location.absUrl()) { + changeCounter++; + $rootScope.$evalAsync(function() { + if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl). + defaultPrevented) { + $location.$$parse(oldUrl); + } else { + $browser.url($location.absUrl(), currentReplace); + afterLocationChange(oldUrl); + } + }); + } + $location.$$replace = false; + + return changeCounter; + }); + + return $location; + + function afterLocationChange(oldUrl) { + $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl); + } +}]; +} + +/** + * @ngdoc object + * @name ng.$log + * @requires $window + * + * @description + * Simple service for logging. Default implementation safely writes the message + * into the browser's console (if present). + * + * The main purpose of this service is to simplify debugging and troubleshooting. + * + * The default is to log `debug` messages. You can use + * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this. + * + * @example + + + function LogCtrl($scope, $log) { + $scope.$log = $log; + $scope.message = 'Hello World!'; + } + + +
+

Reload this page with open console, enter text and hit the log button...

+ Message: + + + + + +
+
+
+ */ + +/** + * @ngdoc object + * @name ng.$logProvider + * @description + * Use the `$logProvider` to configure how the application logs messages + */ +function $LogProvider(){ + var debug = true, + self = this; + + /** + * @ngdoc property + * @name ng.$logProvider#debugEnabled + * @methodOf ng.$logProvider + * @description + * @param {string=} flag enable or disable debug level messages + * @returns {*} current value if used as getter or itself (chaining) if used as setter + */ + this.debugEnabled = function(flag) { + if (isDefined(flag)) { + debug = flag; + return this; + } else { + return debug; + } + }; + + this.$get = ['$window', function($window){ + return { + /** + * @ngdoc method + * @name ng.$log#log + * @methodOf ng.$log + * + * @description + * Write a log message + */ + log: consoleLog('log'), + + /** + * @ngdoc method + * @name ng.$log#info + * @methodOf ng.$log + * + * @description + * Write an information message + */ + info: consoleLog('info'), + + /** + * @ngdoc method + * @name ng.$log#warn + * @methodOf ng.$log + * + * @description + * Write a warning message + */ + warn: consoleLog('warn'), + + /** + * @ngdoc method + * @name ng.$log#error + * @methodOf ng.$log + * + * @description + * Write an error message + */ + error: consoleLog('error'), + + /** + * @ngdoc method + * @name ng.$log#debug + * @methodOf ng.$log + * + * @description + * Write a debug message + */ + debug: (function () { + var fn = consoleLog('debug'); + + return function() { + if (debug) { + fn.apply(self, arguments); + } + }; + }()) + }; + + function formatError(arg) { + if (arg instanceof Error) { + if (arg.stack) { + arg = (arg.message && arg.stack.indexOf(arg.message) === -1) + ? 'Error: ' + arg.message + '\n' + arg.stack + : arg.stack; + } else if (arg.sourceURL) { + arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line; + } + } + return arg; + } + + function consoleLog(type) { + var console = $window.console || {}, + logFn = console[type] || console.log || noop; + + if (logFn.apply) { + return function() { + var args = []; + forEach(arguments, function(arg) { + args.push(formatError(arg)); + }); + return logFn.apply(console, args); + }; + } + + // we are IE which either doesn't have window.console => this is noop and we do nothing, + // or we are IE where console.log doesn't have apply so we log at least first 2 args + return function(arg1, arg2) { + logFn(arg1, arg2 == null ? '' : arg2); + }; + } + }]; +} + +var $parseMinErr = minErr('$parse'); +var promiseWarningCache = {}; +var promiseWarning; + +// Sandboxing Angular Expressions +// ------------------------------ +// Angular expressions are generally considered safe because these expressions only have direct +// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by +// obtaining a reference to native JS functions such as the Function constructor. +// +// As an example, consider the following Angular expression: +// +// {}.toString.constructor(alert("evil JS code")) +// +// We want to prevent this type of access. For the sake of performance, during the lexing phase we +// disallow any "dotted" access to any member named "constructor". +// +// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor +// while evaluating the expression, which is a stronger but more expensive test. Since reflective +// calls are expensive anyway, this is not such a big deal compared to static dereferencing. +// +// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits +// against the expression language, but not to prevent exploits that were enabled by exposing +// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good +// practice and therefore we are not even trying to protect against interaction with an object +// explicitly exposed in this way. +// +// A developer could foil the name check by aliasing the Function constructor under a different +// name on the scope. +// +// In general, it is not possible to access a Window object from an angular expression unless a +// window or some DOM object that has a reference to window is published onto a Scope. + +function ensureSafeMemberName(name, fullExpression) { + if (name === "constructor") { + throw $parseMinErr('isecfld', + 'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } + return name; +} + +function ensureSafeObject(obj, fullExpression) { + // nifty check if obj is Function that is fast and works across iframes and other contexts + if (obj && obj.constructor === obj) { + throw $parseMinErr('isecfn', + 'Referencing Function in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (// isWindow(obj) + obj && obj.document && obj.location && obj.alert && obj.setInterval) { + throw $parseMinErr('isecwindow', + 'Referencing the Window in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (// isElement(obj) + obj && (obj.nodeName || (obj.on && obj.find))) { + throw $parseMinErr('isecdom', + 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else { + return obj; + } +} + +var OPERATORS = { + /* jshint bitwise : false */ + 'null':function(){return null;}, + 'true':function(){return true;}, + 'false':function(){return false;}, + undefined:noop, + '+':function(self, locals, a,b){ + a=a(self, locals); b=b(self, locals); + if (isDefined(a)) { + if (isDefined(b)) { + return a + b; + } + return a; + } + return isDefined(b)?b:undefined;}, + '-':function(self, locals, a,b){ + a=a(self, locals); b=b(self, locals); + return (isDefined(a)?a:0)-(isDefined(b)?b:0); + }, + '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);}, + '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);}, + '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);}, + '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);}, + '=':noop, + '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);}, + '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);}, + '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);}, + '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);}, + '<':function(self, locals, a,b){return a(self, locals)':function(self, locals, a,b){return a(self, locals)>b(self, locals);}, + '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);}, + '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);}, + '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);}, + '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);}, + '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);}, +// '|':function(self, locals, a,b){return a|b;}, + '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));}, + '!':function(self, locals, a){return !a(self, locals);} +}; +/* jshint bitwise: true */ +var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'}; + + +///////////////////////////////////////// + + +/** + * @constructor + */ +var Lexer = function (options) { + this.options = options; +}; + +Lexer.prototype = { + constructor: Lexer, + + lex: function (text) { + this.text = text; + + this.index = 0; + this.ch = undefined; + this.lastCh = ':'; // can start regexp + + this.tokens = []; + + var token; + var json = []; + + while (this.index < this.text.length) { + this.ch = this.text.charAt(this.index); + if (this.is('"\'')) { + this.readString(this.ch); + } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) { + this.readNumber(); + } else if (this.isIdent(this.ch)) { + this.readIdent(); + // identifiers can only be if the preceding char was a { or , + if (this.was('{,') && json[0] === '{' && + (token = this.tokens[this.tokens.length - 1])) { + token.json = token.text.indexOf('.') === -1; + } + } else if (this.is('(){}[].,;:?')) { + this.tokens.push({ + index: this.index, + text: this.ch, + json: (this.was(':[,') && this.is('{[')) || this.is('}]:,') + }); + if (this.is('{[')) json.unshift(this.ch); + if (this.is('}]')) json.shift(); + this.index++; + } else if (this.isWhitespace(this.ch)) { + this.index++; + continue; + } else { + var ch2 = this.ch + this.peek(); + var ch3 = ch2 + this.peek(2); + var fn = OPERATORS[this.ch]; + var fn2 = OPERATORS[ch2]; + var fn3 = OPERATORS[ch3]; + if (fn3) { + this.tokens.push({index: this.index, text: ch3, fn: fn3}); + this.index += 3; + } else if (fn2) { + this.tokens.push({index: this.index, text: ch2, fn: fn2}); + this.index += 2; + } else if (fn) { + this.tokens.push({ + index: this.index, + text: this.ch, + fn: fn, + json: (this.was('[,:') && this.is('+-')) + }); + this.index += 1; + } else { + this.throwError('Unexpected next character ', this.index, this.index + 1); + } + } + this.lastCh = this.ch; + } + return this.tokens; + }, + + is: function(chars) { + return chars.indexOf(this.ch) !== -1; + }, + + was: function(chars) { + return chars.indexOf(this.lastCh) !== -1; + }, + + peek: function(i) { + var num = i || 1; + return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false; + }, + + isNumber: function(ch) { + return ('0' <= ch && ch <= '9'); + }, + + isWhitespace: function(ch) { + // IE treats non-breaking space as \u00A0 + return (ch === ' ' || ch === '\r' || ch === '\t' || + ch === '\n' || ch === '\v' || ch === '\u00A0'); + }, + + isIdent: function(ch) { + return ('a' <= ch && ch <= 'z' || + 'A' <= ch && ch <= 'Z' || + '_' === ch || ch === '$'); + }, + + isExpOperator: function(ch) { + return (ch === '-' || ch === '+' || this.isNumber(ch)); + }, + + throwError: function(error, start, end) { + end = end || this.index; + var colStr = (isDefined(start) + ? 's ' + start + '-' + this.index + ' [' + this.text.substring(start, end) + ']' + : ' ' + end); + throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].', + error, colStr, this.text); + }, + + readNumber: function() { + var number = ''; + var start = this.index; + while (this.index < this.text.length) { + var ch = lowercase(this.text.charAt(this.index)); + if (ch == '.' || this.isNumber(ch)) { + number += ch; + } else { + var peekCh = this.peek(); + if (ch == 'e' && this.isExpOperator(peekCh)) { + number += ch; + } else if (this.isExpOperator(ch) && + peekCh && this.isNumber(peekCh) && + number.charAt(number.length - 1) == 'e') { + number += ch; + } else if (this.isExpOperator(ch) && + (!peekCh || !this.isNumber(peekCh)) && + number.charAt(number.length - 1) == 'e') { + this.throwError('Invalid exponent'); + } else { + break; + } + } + this.index++; + } + number = 1 * number; + this.tokens.push({ + index: start, + text: number, + json: true, + fn: function() { return number; } + }); + }, + + readIdent: function() { + var parser = this; + + var ident = ''; + var start = this.index; + + var lastDot, peekIndex, methodName, ch; + + while (this.index < this.text.length) { + ch = this.text.charAt(this.index); + if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) { + if (ch === '.') lastDot = this.index; + ident += ch; + } else { + break; + } + this.index++; + } + + //check if this is not a method invocation and if it is back out to last dot + if (lastDot) { + peekIndex = this.index; + while (peekIndex < this.text.length) { + ch = this.text.charAt(peekIndex); + if (ch === '(') { + methodName = ident.substr(lastDot - start + 1); + ident = ident.substr(0, lastDot - start); + this.index = peekIndex; + break; + } + if (this.isWhitespace(ch)) { + peekIndex++; + } else { + break; + } + } + } + + + var token = { + index: start, + text: ident + }; + + // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn + if (OPERATORS.hasOwnProperty(ident)) { + token.fn = OPERATORS[ident]; + token.json = OPERATORS[ident]; + } else { + var getter = getterFn(ident, this.options, this.text); + token.fn = extend(function(self, locals) { + return (getter(self, locals)); + }, { + assign: function(self, value) { + return setter(self, ident, value, parser.text, parser.options); + } + }); + } + + this.tokens.push(token); + + if (methodName) { + this.tokens.push({ + index:lastDot, + text: '.', + json: false + }); + this.tokens.push({ + index: lastDot + 1, + text: methodName, + json: false + }); + } + }, + + readString: function(quote) { + var start = this.index; + this.index++; + var string = ''; + var rawString = quote; + var escape = false; + while (this.index < this.text.length) { + var ch = this.text.charAt(this.index); + rawString += ch; + if (escape) { + if (ch === 'u') { + var hex = this.text.substring(this.index + 1, this.index + 5); + if (!hex.match(/[\da-f]{4}/i)) + this.throwError('Invalid unicode escape [\\u' + hex + ']'); + this.index += 4; + string += String.fromCharCode(parseInt(hex, 16)); + } else { + var rep = ESCAPE[ch]; + if (rep) { + string += rep; + } else { + string += ch; + } + } + escape = false; + } else if (ch === '\\') { + escape = true; + } else if (ch === quote) { + this.index++; + this.tokens.push({ + index: start, + text: rawString, + string: string, + json: true, + fn: function() { return string; } + }); + return; + } else { + string += ch; + } + this.index++; + } + this.throwError('Unterminated quote', start); + } +}; + + +/** + * @constructor + */ +var Parser = function (lexer, $filter, options) { + this.lexer = lexer; + this.$filter = $filter; + this.options = options; +}; + +Parser.ZERO = function () { return 0; }; + +Parser.prototype = { + constructor: Parser, + + parse: function (text, json) { + this.text = text; + + //TODO(i): strip all the obsolte json stuff from this file + this.json = json; + + this.tokens = this.lexer.lex(text); + + if (json) { + // The extra level of aliasing is here, just in case the lexer misses something, so that + // we prevent any accidental execution in JSON. + this.assignment = this.logicalOR; + + this.functionCall = + this.fieldAccess = + this.objectIndex = + this.filterChain = function() { + this.throwError('is not valid json', {text: text, index: 0}); + }; + } + + var value = json ? this.primary() : this.statements(); + + if (this.tokens.length !== 0) { + this.throwError('is an unexpected token', this.tokens[0]); + } + + value.literal = !!value.literal; + value.constant = !!value.constant; + + return value; + }, + + primary: function () { + var primary; + if (this.expect('(')) { + primary = this.filterChain(); + this.consume(')'); + } else if (this.expect('[')) { + primary = this.arrayDeclaration(); + } else if (this.expect('{')) { + primary = this.object(); + } else { + var token = this.expect(); + primary = token.fn; + if (!primary) { + this.throwError('not a primary expression', token); + } + if (token.json) { + primary.constant = true; + primary.literal = true; + } + } + + var next, context; + while ((next = this.expect('(', '[', '.'))) { + if (next.text === '(') { + primary = this.functionCall(primary, context); + context = null; + } else if (next.text === '[') { + context = primary; + primary = this.objectIndex(primary); + } else if (next.text === '.') { + context = primary; + primary = this.fieldAccess(primary); + } else { + this.throwError('IMPOSSIBLE'); + } + } + return primary; + }, + + throwError: function(msg, token) { + throw $parseMinErr('syntax', + 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].', + token.text, msg, (token.index + 1), this.text, this.text.substring(token.index)); + }, + + peekToken: function() { + if (this.tokens.length === 0) + throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text); + return this.tokens[0]; + }, + + peek: function(e1, e2, e3, e4) { + if (this.tokens.length > 0) { + var token = this.tokens[0]; + var t = token.text; + if (t === e1 || t === e2 || t === e3 || t === e4 || + (!e1 && !e2 && !e3 && !e4)) { + return token; + } + } + return false; + }, + + expect: function(e1, e2, e3, e4){ + var token = this.peek(e1, e2, e3, e4); + if (token) { + if (this.json && !token.json) { + this.throwError('is not valid json', token); + } + this.tokens.shift(); + return token; + } + return false; + }, + + consume: function(e1){ + if (!this.expect(e1)) { + this.throwError('is unexpected, expecting [' + e1 + ']', this.peek()); + } + }, + + unaryFn: function(fn, right) { + return extend(function(self, locals) { + return fn(self, locals, right); + }, { + constant:right.constant + }); + }, + + ternaryFn: function(left, middle, right){ + return extend(function(self, locals){ + return left(self, locals) ? middle(self, locals) : right(self, locals); + }, { + constant: left.constant && middle.constant && right.constant + }); + }, + + binaryFn: function(left, fn, right) { + return extend(function(self, locals) { + return fn(self, locals, left, right); + }, { + constant:left.constant && right.constant + }); + }, + + statements: function() { + var statements = []; + while (true) { + if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']')) + statements.push(this.filterChain()); + if (!this.expect(';')) { + // optimize for the common case where there is only one statement. + // TODO(size): maybe we should not support multiple statements? + return (statements.length === 1) + ? statements[0] + : function(self, locals) { + var value; + for (var i = 0; i < statements.length; i++) { + var statement = statements[i]; + if (statement) { + value = statement(self, locals); + } + } + return value; + }; + } + } + }, + + filterChain: function() { + var left = this.expression(); + var token; + while (true) { + if ((token = this.expect('|'))) { + left = this.binaryFn(left, token.fn, this.filter()); + } else { + return left; + } + } + }, + + filter: function() { + var token = this.expect(); + var fn = this.$filter(token.text); + var argsFn = []; + while (true) { + if ((token = this.expect(':'))) { + argsFn.push(this.expression()); + } else { + var fnInvoke = function(self, locals, input) { + var args = [input]; + for (var i = 0; i < argsFn.length; i++) { + args.push(argsFn[i](self, locals)); + } + return fn.apply(self, args); + }; + return function() { + return fnInvoke; + }; + } + } + }, + + expression: function() { + return this.assignment(); + }, + + assignment: function() { + var left = this.ternary(); + var right; + var token; + if ((token = this.expect('='))) { + if (!left.assign) { + this.throwError('implies assignment but [' + + this.text.substring(0, token.index) + '] can not be assigned to', token); + } + right = this.ternary(); + return function(scope, locals) { + return left.assign(scope, right(scope, locals), locals); + }; + } + return left; + }, + + ternary: function() { + var left = this.logicalOR(); + var middle; + var token; + if ((token = this.expect('?'))) { + middle = this.ternary(); + if ((token = this.expect(':'))) { + return this.ternaryFn(left, middle, this.ternary()); + } else { + this.throwError('expected :', token); + } + } else { + return left; + } + }, + + logicalOR: function() { + var left = this.logicalAND(); + var token; + while (true) { + if ((token = this.expect('||'))) { + left = this.binaryFn(left, token.fn, this.logicalAND()); + } else { + return left; + } + } + }, + + logicalAND: function() { + var left = this.equality(); + var token; + if ((token = this.expect('&&'))) { + left = this.binaryFn(left, token.fn, this.logicalAND()); + } + return left; + }, + + equality: function() { + var left = this.relational(); + var token; + if ((token = this.expect('==','!=','===','!=='))) { + left = this.binaryFn(left, token.fn, this.equality()); + } + return left; + }, + + relational: function() { + var left = this.additive(); + var token; + if ((token = this.expect('<', '>', '<=', '>='))) { + left = this.binaryFn(left, token.fn, this.relational()); + } + return left; + }, + + additive: function() { + var left = this.multiplicative(); + var token; + while ((token = this.expect('+','-'))) { + left = this.binaryFn(left, token.fn, this.multiplicative()); + } + return left; + }, + + multiplicative: function() { + var left = this.unary(); + var token; + while ((token = this.expect('*','/','%'))) { + left = this.binaryFn(left, token.fn, this.unary()); + } + return left; + }, + + unary: function() { + var token; + if (this.expect('+')) { + return this.primary(); + } else if ((token = this.expect('-'))) { + return this.binaryFn(Parser.ZERO, token.fn, this.unary()); + } else if ((token = this.expect('!'))) { + return this.unaryFn(token.fn, this.unary()); + } else { + return this.primary(); + } + }, + + fieldAccess: function(object) { + var parser = this; + var field = this.expect().text; + var getter = getterFn(field, this.options, this.text); + + return extend(function(scope, locals, self) { + return getter(self || object(scope, locals), locals); + }, { + assign: function(scope, value, locals) { + return setter(object(scope, locals), field, value, parser.text, parser.options); + } + }); + }, + + objectIndex: function(obj) { + var parser = this; + + var indexFn = this.expression(); + this.consume(']'); + + return extend(function(self, locals) { + var o = obj(self, locals), + i = indexFn(self, locals), + v, p; + + if (!o) return undefined; + v = ensureSafeObject(o[i], parser.text); + if (v && v.then && parser.options.unwrapPromises) { + p = v; + if (!('$$v' in v)) { + p.$$v = undefined; + p.then(function(val) { p.$$v = val; }); + } + v = v.$$v; + } + return v; + }, { + assign: function(self, value, locals) { + var key = indexFn(self, locals); + // prevent overwriting of Function.constructor which would break ensureSafeObject check + var safe = ensureSafeObject(obj(self, locals), parser.text); + return safe[key] = value; + } + }); + }, + + functionCall: function(fn, contextGetter) { + var argsFn = []; + if (this.peekToken().text !== ')') { + do { + argsFn.push(this.expression()); + } while (this.expect(',')); + } + this.consume(')'); + + var parser = this; + + return function(scope, locals) { + var args = []; + var context = contextGetter ? contextGetter(scope, locals) : scope; + + for (var i = 0; i < argsFn.length; i++) { + args.push(argsFn[i](scope, locals)); + } + var fnPtr = fn(scope, locals, context) || noop; + + ensureSafeObject(context, parser.text); + ensureSafeObject(fnPtr, parser.text); + + // IE stupidity! (IE doesn't have apply for some native functions) + var v = fnPtr.apply + ? fnPtr.apply(context, args) + : fnPtr(args[0], args[1], args[2], args[3], args[4]); + + return ensureSafeObject(v, parser.text); + }; + }, + + // This is used with json array declaration + arrayDeclaration: function () { + var elementFns = []; + var allConstant = true; + if (this.peekToken().text !== ']') { + do { + var elementFn = this.expression(); + elementFns.push(elementFn); + if (!elementFn.constant) { + allConstant = false; + } + } while (this.expect(',')); + } + this.consume(']'); + + return extend(function(self, locals) { + var array = []; + for (var i = 0; i < elementFns.length; i++) { + array.push(elementFns[i](self, locals)); + } + return array; + }, { + literal: true, + constant: allConstant + }); + }, + + object: function () { + var keyValues = []; + var allConstant = true; + if (this.peekToken().text !== '}') { + do { + var token = this.expect(), + key = token.string || token.text; + this.consume(':'); + var value = this.expression(); + keyValues.push({key: key, value: value}); + if (!value.constant) { + allConstant = false; + } + } while (this.expect(',')); + } + this.consume('}'); + + return extend(function(self, locals) { + var object = {}; + for (var i = 0; i < keyValues.length; i++) { + var keyValue = keyValues[i]; + object[keyValue.key] = keyValue.value(self, locals); + } + return object; + }, { + literal: true, + constant: allConstant + }); + } +}; + + +////////////////////////////////////////////////// +// Parser helper functions +////////////////////////////////////////////////// + +function setter(obj, path, setValue, fullExp, options) { + //needed? + options = options || {}; + + var element = path.split('.'), key; + for (var i = 0; element.length > 1; i++) { + key = ensureSafeMemberName(element.shift(), fullExp); + var propertyObj = obj[key]; + if (!propertyObj) { + propertyObj = {}; + obj[key] = propertyObj; + } + obj = propertyObj; + if (obj.then && options.unwrapPromises) { + promiseWarning(fullExp); + if (!("$$v" in obj)) { + (function(promise) { + promise.then(function(val) { promise.$$v = val; }); } + )(obj); + } + if (obj.$$v === undefined) { + obj.$$v = {}; + } + obj = obj.$$v; + } + } + key = ensureSafeMemberName(element.shift(), fullExp); + obj[key] = setValue; + return setValue; +} + +var getterFnCache = {}; + +/** + * Implementation of the "Black Hole" variant from: + * - http://jsperf.com/angularjs-parse-getter/4 + * - http://jsperf.com/path-evaluation-simplified/7 + */ +function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) { + ensureSafeMemberName(key0, fullExp); + ensureSafeMemberName(key1, fullExp); + ensureSafeMemberName(key2, fullExp); + ensureSafeMemberName(key3, fullExp); + ensureSafeMemberName(key4, fullExp); + + return !options.unwrapPromises + ? function cspSafeGetter(scope, locals) { + var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope; + + if (pathVal === null || pathVal === undefined) return pathVal; + pathVal = pathVal[key0]; + + if (!key1 || pathVal === null || pathVal === undefined) return pathVal; + pathVal = pathVal[key1]; + + if (!key2 || pathVal === null || pathVal === undefined) return pathVal; + pathVal = pathVal[key2]; + + if (!key3 || pathVal === null || pathVal === undefined) return pathVal; + pathVal = pathVal[key3]; + + if (!key4 || pathVal === null || pathVal === undefined) return pathVal; + pathVal = pathVal[key4]; + + return pathVal; + } + : function cspSafePromiseEnabledGetter(scope, locals) { + var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope, + promise; + + if (pathVal === null || pathVal === undefined) return pathVal; + + pathVal = pathVal[key0]; + if (pathVal && pathVal.then) { + promiseWarning(fullExp); + if (!("$$v" in pathVal)) { + promise = pathVal; + promise.$$v = undefined; + promise.then(function(val) { promise.$$v = val; }); + } + pathVal = pathVal.$$v; + } + if (!key1 || pathVal === null || pathVal === undefined) return pathVal; + + pathVal = pathVal[key1]; + if (pathVal && pathVal.then) { + promiseWarning(fullExp); + if (!("$$v" in pathVal)) { + promise = pathVal; + promise.$$v = undefined; + promise.then(function(val) { promise.$$v = val; }); + } + pathVal = pathVal.$$v; + } + if (!key2 || pathVal === null || pathVal === undefined) return pathVal; + + pathVal = pathVal[key2]; + if (pathVal && pathVal.then) { + promiseWarning(fullExp); + if (!("$$v" in pathVal)) { + promise = pathVal; + promise.$$v = undefined; + promise.then(function(val) { promise.$$v = val; }); + } + pathVal = pathVal.$$v; + } + if (!key3 || pathVal === null || pathVal === undefined) return pathVal; + + pathVal = pathVal[key3]; + if (pathVal && pathVal.then) { + promiseWarning(fullExp); + if (!("$$v" in pathVal)) { + promise = pathVal; + promise.$$v = undefined; + promise.then(function(val) { promise.$$v = val; }); + } + pathVal = pathVal.$$v; + } + if (!key4 || pathVal === null || pathVal === undefined) return pathVal; + + pathVal = pathVal[key4]; + if (pathVal && pathVal.then) { + promiseWarning(fullExp); + if (!("$$v" in pathVal)) { + promise = pathVal; + promise.$$v = undefined; + promise.then(function(val) { promise.$$v = val; }); + } + pathVal = pathVal.$$v; + } + return pathVal; + }; +} + +function getterFn(path, options, fullExp) { + // Check whether the cache has this getter already. + // We can use hasOwnProperty directly on the cache because we ensure, + // see below, that the cache never stores a path called 'hasOwnProperty' + if (getterFnCache.hasOwnProperty(path)) { + return getterFnCache[path]; + } + + var pathKeys = path.split('.'), + pathKeysLength = pathKeys.length, + fn; + + if (options.csp) { + if (pathKeysLength < 6) { + fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp, + options); + } else { + fn = function(scope, locals) { + var i = 0, val; + do { + val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], + pathKeys[i++], fullExp, options)(scope, locals); + + locals = undefined; // clear after first iteration + scope = val; + } while (i < pathKeysLength); + return val; + }; + } + } else { + var code = 'var l, fn, p;\n'; + forEach(pathKeys, function(key, index) { + ensureSafeMemberName(key, fullExp); + code += 'if(s === null || s === undefined) return s;\n' + + 'l=s;\n' + + 's='+ (index + // we simply dereference 's' on any .dot notation + ? 's' + // but if we are first then we check locals first, and if so read it first + : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' + + (options.unwrapPromises + ? 'if (s && s.then) {\n' + + ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' + + ' if (!("$$v" in s)) {\n' + + ' p=s;\n' + + ' p.$$v = undefined;\n' + + ' p.then(function(v) {p.$$v=v;});\n' + + '}\n' + + ' s=s.$$v\n' + + '}\n' + : ''); + }); + code += 'return s;'; + + /* jshint -W054 */ + var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning + /* jshint +W054 */ + evaledFnGetter.toString = function() { return code; }; + fn = function(scope, locals) { + return evaledFnGetter(scope, locals, promiseWarning); + }; + } + + // Only cache the value if it's not going to mess up the cache object + // This is more performant that using Object.prototype.hasOwnProperty.call + if (path !== 'hasOwnProperty') { + getterFnCache[path] = fn; + } + return fn; +} + +/////////////////////////////////// + +/** + * @ngdoc function + * @name ng.$parse + * @function + * + * @description + * + * Converts Angular {@link guide/expression expression} into a function. + * + *
+ *   var getter = $parse('user.name');
+ *   var setter = getter.assign;
+ *   var context = {user:{name:'angular'}};
+ *   var locals = {user:{name:'local'}};
+ *
+ *   expect(getter(context)).toEqual('angular');
+ *   setter(context, 'newValue');
+ *   expect(context.user.name).toEqual('newValue');
+ *   expect(getter(context, locals)).toEqual('local');
+ * 
+ * + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + * + * The returned function also has the following properties: + * * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript + * literal. + * * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript + * constant literals. + * * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be + * set to a function to change its value on the given context. + * + */ + + +/** + * @ngdoc object + * @name ng.$parseProvider + * @function + * + * @description + * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse} + * service. + */ +function $ParseProvider() { + var cache = {}; + + var $parseOptions = { + csp: false, + unwrapPromises: false, + logPromiseWarnings: true + }; + + + /** + * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future. + * + * @ngdoc method + * @name ng.$parseProvider#unwrapPromises + * @methodOf ng.$parseProvider + * @description + * + * **This feature is deprecated, see deprecation notes below for more info** + * + * If set to true (default is false), $parse will unwrap promises automatically when a promise is + * found at any part of the expression. In other words, if set to true, the expression will always + * result in a non-promise value. + * + * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled, + * the fulfillment value is used in place of the promise while evaluating the expression. + * + * **Deprecation notice** + * + * This is a feature that didn't prove to be wildly useful or popular, primarily because of the + * dichotomy between data access in templates (accessed as raw values) and controller code + * (accessed as promises). + * + * In most code we ended up resolving promises manually in controllers anyway and thus unifying + * the model access there. + * + * Other downsides of automatic promise unwrapping: + * + * - when building components it's often desirable to receive the raw promises + * - adds complexity and slows down expression evaluation + * - makes expression code pre-generation unattractive due to the amount of code that needs to be + * generated + * - makes IDE auto-completion and tool support hard + * + * **Warning Logs** + * + * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a + * promise (to reduce the noise, each expression is logged only once). To disable this logging use + * `$parseProvider.logPromiseWarnings(false)` api. + * + * + * @param {boolean=} value New value. + * @returns {boolean|self} Returns the current setting when used as getter and self if used as + * setter. + */ + this.unwrapPromises = function(value) { + if (isDefined(value)) { + $parseOptions.unwrapPromises = !!value; + return this; + } else { + return $parseOptions.unwrapPromises; + } + }; + + + /** + * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future. + * + * @ngdoc method + * @name ng.$parseProvider#logPromiseWarnings + * @methodOf ng.$parseProvider + * @description + * + * Controls whether Angular should log a warning on any encounter of a promise in an expression. + * + * The default is set to `true`. + * + * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well. + * + * @param {boolean=} value New value. + * @returns {boolean|self} Returns the current setting when used as getter and self if used as + * setter. + */ + this.logPromiseWarnings = function(value) { + if (isDefined(value)) { + $parseOptions.logPromiseWarnings = value; + return this; + } else { + return $parseOptions.logPromiseWarnings; + } + }; + + + this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) { + $parseOptions.csp = $sniffer.csp; + + promiseWarning = function promiseWarningFn(fullExp) { + if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return; + promiseWarningCache[fullExp] = true; + $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' + + 'Automatic unwrapping of promises in Angular expressions is deprecated.'); + }; + + return function(exp) { + var parsedExpression; + + switch (typeof exp) { + case 'string': + + if (cache.hasOwnProperty(exp)) { + return cache[exp]; + } + + var lexer = new Lexer($parseOptions); + var parser = new Parser(lexer, $filter, $parseOptions); + parsedExpression = parser.parse(exp, false); + + if (exp !== 'hasOwnProperty') { + // Only cache the value if it's not going to mess up the cache object + // This is more performant that using Object.prototype.hasOwnProperty.call + cache[exp] = parsedExpression; + } + + return parsedExpression; + + case 'function': + return exp; + + default: + return noop; + } + }; + }]; +} + +/** + * @ngdoc service + * @name ng.$q + * @requires $rootScope + * + * @description + * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q). + * + * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an + * interface for interacting with an object that represents the result of an action that is + * performed asynchronously, and may or may not be finished at any given point in time. + * + * From the perspective of dealing with error handling, deferred and promise APIs are to + * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming. + * + *
+ *   // for the purpose of this example let's assume that variables `$q` and `scope` are
+ *   // available in the current lexical scope (they could have been injected or passed in).
+ *
+ *   function asyncGreet(name) {
+ *     var deferred = $q.defer();
+ *
+ *     setTimeout(function() {
+ *       // since this fn executes async in a future turn of the event loop, we need to wrap
+ *       // our code into an $apply call so that the model changes are properly observed.
+ *       scope.$apply(function() {
+ *         deferred.notify('About to greet ' + name + '.');
+ *
+ *         if (okToGreet(name)) {
+ *           deferred.resolve('Hello, ' + name + '!');
+ *         } else {
+ *           deferred.reject('Greeting ' + name + ' is not allowed.');
+ *         }
+ *       });
+ *     }, 1000);
+ *
+ *     return deferred.promise;
+ *   }
+ *
+ *   var promise = asyncGreet('Robin Hood');
+ *   promise.then(function(greeting) {
+ *     alert('Success: ' + greeting);
+ *   }, function(reason) {
+ *     alert('Failed: ' + reason);
+ *   }, function(update) {
+ *     alert('Got notification: ' + update);
+ *   });
+ * 
+ * + * At first it might not be obvious why this extra complexity is worth the trouble. The payoff + * comes in the way of guarantees that promise and deferred APIs make, see + * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md. + * + * Additionally the promise api allows for composition that is very hard to do with the + * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach. + * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the + * section on serial or parallel joining of promises. + * + * + * # The Deferred API + * + * A new instance of deferred is constructed by calling `$q.defer()`. + * + * The purpose of the deferred object is to expose the associated Promise instance as well as APIs + * that can be used for signaling the successful or unsuccessful completion, as well as the status + * of the task. + * + * **Methods** + * + * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection + * constructed via `$q.reject`, the promise will be rejected instead. + * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to + * resolving it with a rejection constructed via `$q.reject`. + * - `notify(value)` - provides updates on the status of the promises execution. This may be called + * multiple times before the promise is either resolved or rejected. + * + * **Properties** + * + * - promise – `{Promise}` – promise object associated with this deferred. + * + * + * # The Promise API + * + * A new promise instance is created when a deferred instance is created and can be retrieved by + * calling `deferred.promise`. + * + * The purpose of the promise object is to allow for interested parties to get access to the result + * of the deferred task when it completes. + * + * **Methods** + * + * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or + * will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously + * as soon as the result is available. The callbacks are called with a single argument: the result + * or rejection reason. Additionally, the notify callback may be called zero or more times to + * provide a progress indication, before the promise is resolved or rejected. + * + * This method *returns a new promise* which is resolved or rejected via the return value of the + * `successCallback`, `errorCallback`. It also notifies via the return value of the + * `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback + * method. + * + * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)` + * + * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise, + * but to do so without modifying the final value. This is useful to release resources or do some + * clean-up that needs to be done whether the promise was rejected or resolved. See the [full + * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for + * more information. + * + * Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as + * property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to + * make your code IE8 compatible. + * + * # Chaining promises + * + * Because calling the `then` method of a promise returns a new derived promise, it is easily + * possible to create a chain of promises: + * + *
+ *   promiseB = promiseA.then(function(result) {
+ *     return result + 1;
+ *   });
+ *
+ *   // promiseB will be resolved immediately after promiseA is resolved and its value
+ *   // will be the result of promiseA incremented by 1
+ * 
+ * + * It is possible to create chains of any length and since a promise can be resolved with another + * promise (which will defer its resolution further), it is possible to pause/defer resolution of + * the promises at any point in the chain. This makes it possible to implement powerful APIs like + * $http's response interceptors. + * + * + * # Differences between Kris Kowal's Q and $q + * + * There are three main differences: + * + * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation + * mechanism in angular, which means faster propagation of resolution or rejection into your + * models and avoiding unnecessary browser repaints, which would result in flickering UI. + * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains + * all the important functionality needed for common async tasks. + * + * # Testing + * + *
+ *    it('should simulate promise', inject(function($q, $rootScope) {
+ *      var deferred = $q.defer();
+ *      var promise = deferred.promise;
+ *      var resolvedValue;
+ *
+ *      promise.then(function(value) { resolvedValue = value; });
+ *      expect(resolvedValue).toBeUndefined();
+ *
+ *      // Simulate resolving of promise
+ *      deferred.resolve(123);
+ *      // Note that the 'then' function does not get called synchronously.
+ *      // This is because we want the promise API to always be async, whether or not
+ *      // it got called synchronously or asynchronously.
+ *      expect(resolvedValue).toBeUndefined();
+ *
+ *      // Propagate promise resolution to 'then' functions using $apply().
+ *      $rootScope.$apply();
+ *      expect(resolvedValue).toEqual(123);
+ *    }));
+ *  
+ */ +function $QProvider() { + + this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) { + return qFactory(function(callback) { + $rootScope.$evalAsync(callback); + }, $exceptionHandler); + }]; +} + + +/** + * Constructs a promise manager. + * + * @param {function(function)} nextTick Function for executing functions in the next turn. + * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for + * debugging purposes. + * @returns {object} Promise manager. + */ +function qFactory(nextTick, exceptionHandler) { + + /** + * @ngdoc + * @name ng.$q#defer + * @methodOf ng.$q + * @description + * Creates a `Deferred` object which represents a task which will finish in the future. + * + * @returns {Deferred} Returns a new instance of deferred. + */ + var defer = function() { + var pending = [], + value, deferred; + + deferred = { + + resolve: function(val) { + if (pending) { + var callbacks = pending; + pending = undefined; + value = ref(val); + + if (callbacks.length) { + nextTick(function() { + var callback; + for (var i = 0, ii = callbacks.length; i < ii; i++) { + callback = callbacks[i]; + value.then(callback[0], callback[1], callback[2]); + } + }); + } + } + }, + + + reject: function(reason) { + deferred.resolve(reject(reason)); + }, + + + notify: function(progress) { + if (pending) { + var callbacks = pending; + + if (pending.length) { + nextTick(function() { + var callback; + for (var i = 0, ii = callbacks.length; i < ii; i++) { + callback = callbacks[i]; + callback[2](progress); + } + }); + } + } + }, + + + promise: { + then: function(callback, errback, progressback) { + var result = defer(); + + var wrappedCallback = function(value) { + try { + result.resolve((isFunction(callback) ? callback : defaultCallback)(value)); + } catch(e) { + result.reject(e); + exceptionHandler(e); + } + }; + + var wrappedErrback = function(reason) { + try { + result.resolve((isFunction(errback) ? errback : defaultErrback)(reason)); + } catch(e) { + result.reject(e); + exceptionHandler(e); + } + }; + + var wrappedProgressback = function(progress) { + try { + result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress)); + } catch(e) { + exceptionHandler(e); + } + }; + + if (pending) { + pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]); + } else { + value.then(wrappedCallback, wrappedErrback, wrappedProgressback); + } + + return result.promise; + }, + + "catch": function(callback) { + return this.then(null, callback); + }, + + "finally": function(callback) { + + function makePromise(value, resolved) { + var result = defer(); + if (resolved) { + result.resolve(value); + } else { + result.reject(value); + } + return result.promise; + } + + function handleCallback(value, isResolved) { + var callbackOutput = null; + try { + callbackOutput = (callback ||defaultCallback)(); + } catch(e) { + return makePromise(e, false); + } + if (callbackOutput && isFunction(callbackOutput.then)) { + return callbackOutput.then(function() { + return makePromise(value, isResolved); + }, function(error) { + return makePromise(error, false); + }); + } else { + return makePromise(value, isResolved); + } + } + + return this.then(function(value) { + return handleCallback(value, true); + }, function(error) { + return handleCallback(error, false); + }); + } + } + }; + + return deferred; + }; + + + var ref = function(value) { + if (value && isFunction(value.then)) return value; + return { + then: function(callback) { + var result = defer(); + nextTick(function() { + result.resolve(callback(value)); + }); + return result.promise; + } + }; + }; + + + /** + * @ngdoc + * @name ng.$q#reject + * @methodOf ng.$q + * @description + * Creates a promise that is resolved as rejected with the specified `reason`. This api should be + * used to forward rejection in a chain of promises. If you are dealing with the last promise in + * a promise chain, you don't need to worry about it. + * + * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of + * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via + * a promise error callback and you want to forward the error to the promise derived from the + * current promise, you have to "rethrow" the error by returning a rejection constructed via + * `reject`. + * + *
+   *   promiseB = promiseA.then(function(result) {
+   *     // success: do something and resolve promiseB
+   *     //          with the old or a new result
+   *     return result;
+   *   }, function(reason) {
+   *     // error: handle the error if possible and
+   *     //        resolve promiseB with newPromiseOrValue,
+   *     //        otherwise forward the rejection to promiseB
+   *     if (canHandle(reason)) {
+   *      // handle the error and recover
+   *      return newPromiseOrValue;
+   *     }
+   *     return $q.reject(reason);
+   *   });
+   * 
+ * + * @param {*} reason Constant, message, exception or an object representing the rejection reason. + * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`. + */ + var reject = function(reason) { + return { + then: function(callback, errback) { + var result = defer(); + nextTick(function() { + try { + result.resolve((isFunction(errback) ? errback : defaultErrback)(reason)); + } catch(e) { + result.reject(e); + exceptionHandler(e); + } + }); + return result.promise; + } + }; + }; + + + /** + * @ngdoc + * @name ng.$q#when + * @methodOf ng.$q + * @description + * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. + * This is useful when you are dealing with an object that might or might not be a promise, or if + * the promise comes from a source that can't be trusted. + * + * @param {*} value Value or a promise + * @returns {Promise} Returns a promise of the passed value or promise + */ + var when = function(value, callback, errback, progressback) { + var result = defer(), + done; + + var wrappedCallback = function(value) { + try { + return (isFunction(callback) ? callback : defaultCallback)(value); + } catch (e) { + exceptionHandler(e); + return reject(e); + } + }; + + var wrappedErrback = function(reason) { + try { + return (isFunction(errback) ? errback : defaultErrback)(reason); + } catch (e) { + exceptionHandler(e); + return reject(e); + } + }; + + var wrappedProgressback = function(progress) { + try { + return (isFunction(progressback) ? progressback : defaultCallback)(progress); + } catch (e) { + exceptionHandler(e); + } + }; + + nextTick(function() { + ref(value).then(function(value) { + if (done) return; + done = true; + result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback)); + }, function(reason) { + if (done) return; + done = true; + result.resolve(wrappedErrback(reason)); + }, function(progress) { + if (done) return; + result.notify(wrappedProgressback(progress)); + }); + }); + + return result.promise; + }; + + + function defaultCallback(value) { + return value; + } + + + function defaultErrback(reason) { + return reject(reason); + } + + + /** + * @ngdoc + * @name ng.$q#all + * @methodOf ng.$q + * @description + * Combines multiple promises into a single promise that is resolved when all of the input + * promises are resolved. + * + * @param {Array.|Object.} promises An array or hash of promises. + * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values, + * each value corresponding to the promise at the same index/key in the `promises` array/hash. + * If any of the promises is resolved with a rejection, this resulting promise will be rejected + * with the same rejection value. + */ + function all(promises) { + var deferred = defer(), + counter = 0, + results = isArray(promises) ? [] : {}; + + forEach(promises, function(promise, key) { + counter++; + ref(promise).then(function(value) { + if (results.hasOwnProperty(key)) return; + results[key] = value; + if (!(--counter)) deferred.resolve(results); + }, function(reason) { + if (results.hasOwnProperty(key)) return; + deferred.reject(reason); + }); + }); + + if (counter === 0) { + deferred.resolve(results); + } + + return deferred.promise; + } + + return { + defer: defer, + reject: reject, + when: when, + all: all + }; +} + +/** + * DESIGN NOTES + * + * The design decisions behind the scope are heavily favored for speed and memory consumption. + * + * The typical use of scope is to watch the expressions, which most of the time return the same + * value as last time so we optimize the operation. + * + * Closures construction is expensive in terms of speed as well as memory: + * - No closures, instead use prototypical inheritance for API + * - Internal state needs to be stored on scope directly, which means that private state is + * exposed as $$____ properties + * + * Loop operations are optimized by using while(count--) { ... } + * - this means that in order to keep the same order of execution as addition we have to add + * items to the array at the beginning (shift) instead of at the end (push) + * + * Child scopes are created and removed often + * - Using an array would be slow since inserts in middle are expensive so we use linked list + * + * There are few watches then a lot of observers. This is why you don't want the observer to be + * implemented in the same way as watch. Watch requires return of initialization function which + * are expensive to construct. + */ + + +/** + * @ngdoc object + * @name ng.$rootScopeProvider + * @description + * + * Provider for the $rootScope service. + */ + +/** + * @ngdoc function + * @name ng.$rootScopeProvider#digestTtl + * @methodOf ng.$rootScopeProvider + * @description + * + * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and + * assuming that the model is unstable. + * + * The current default is 10 iterations. + * + * In complex applications it's possible that the dependencies between `$watch`s will result in + * several digest iterations. However if an application needs more than the default 10 digest + * iterations for its model to stabilize then you should investigate what is causing the model to + * continuously change during the digest. + * + * Increasing the TTL could have performance implications, so you should not change it without + * proper justification. + * + * @param {number} limit The number of digest iterations. + */ + + +/** + * @ngdoc object + * @name ng.$rootScope + * @description + * + * Every application has a single root {@link ng.$rootScope.Scope scope}. + * All other scopes are descendant scopes of the root scope. Scopes provide separation + * between the model and the view, via a mechanism for watching the model for changes. + * They also provide an event emission/broadcast and subscription facility. See the + * {@link guide/scope developer guide on scopes}. + */ +function $RootScopeProvider(){ + var TTL = 10; + var $rootScopeMinErr = minErr('$rootScope'); + + this.digestTtl = function(value) { + if (arguments.length) { + TTL = value; + } + return TTL; + }; + + this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser', + function( $injector, $exceptionHandler, $parse, $browser) { + + /** + * @ngdoc function + * @name ng.$rootScope.Scope + * + * @description + * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the + * {@link AUTO.$injector $injector}. Child scopes are created using the + * {@link ng.$rootScope.Scope#methods_$new $new()} method. (Most scopes are created automatically when + * compiled HTML template is executed.) + * + * Here is a simple scope snippet to show how you can interact with the scope. + *
+     * 
+     * 
+ * + * # Inheritance + * A scope can inherit from a parent scope, as in this example: + *
+         var parent = $rootScope;
+         var child = parent.$new();
+
+         parent.salutation = "Hello";
+         child.name = "World";
+         expect(child.salutation).toEqual('Hello');
+
+         child.salutation = "Welcome";
+         expect(child.salutation).toEqual('Welcome');
+         expect(parent.salutation).toEqual('Hello');
+     * 
+ * + * + * @param {Object.=} providers Map of service factory which need to be + * provided for the current scope. Defaults to {@link ng}. + * @param {Object.=} instanceCache Provides pre-instantiated services which should + * append/override services provided by `providers`. This is handy + * when unit-testing and having the need to override a default + * service. + * @returns {Object} Newly created scope. + * + */ + function Scope() { + this.$id = nextUid(); + this.$$phase = this.$parent = this.$$watchers = + this.$$nextSibling = this.$$prevSibling = + this.$$childHead = this.$$childTail = null; + this['this'] = this.$root = this; + this.$$destroyed = false; + this.$$asyncQueue = []; + this.$$postDigestQueue = []; + this.$$listeners = {}; + this.$$isolateBindings = {}; + } + + /** + * @ngdoc property + * @name ng.$rootScope.Scope#$id + * @propertyOf ng.$rootScope.Scope + * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for + * debugging. + */ + + + Scope.prototype = { + constructor: Scope, + /** + * @ngdoc function + * @name ng.$rootScope.Scope#$new + * @methodOf ng.$rootScope.Scope + * @function + * + * @description + * Creates a new child {@link ng.$rootScope.Scope scope}. + * + * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and + * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the + * scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}. + * + * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is + * desired for the scope and its child scopes to be permanently detached from the parent and + * thus stop participating in model change detection and listener notification by invoking. + * + * @param {boolean} isolate If true, then the scope does not prototypically inherit from the + * parent scope. The scope is isolated, as it can not see parent scope properties. + * When creating widgets, it is useful for the widget to not accidentally read parent + * state. + * + * @returns {Object} The newly created child scope. + * + */ + $new: function(isolate) { + var Child, + child; + + if (isolate) { + child = new Scope(); + child.$root = this.$root; + // ensure that there is just one async queue per $rootScope and its children + child.$$asyncQueue = this.$$asyncQueue; + child.$$postDigestQueue = this.$$postDigestQueue; + } else { + Child = function() {}; // should be anonymous; This is so that when the minifier munges + // the name it does not become random set of chars. This will then show up as class + // name in the debugger. + Child.prototype = this; + child = new Child(); + child.$id = nextUid(); + } + child['this'] = child; + child.$$listeners = {}; + child.$parent = this; + child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null; + child.$$prevSibling = this.$$childTail; + if (this.$$childHead) { + this.$$childTail.$$nextSibling = child; + this.$$childTail = child; + } else { + this.$$childHead = this.$$childTail = child; + } + return child; + }, + + /** + * @ngdoc function + * @name ng.$rootScope.Scope#$watch + * @methodOf ng.$rootScope.Scope + * @function + * + * @description + * Registers a `listener` callback to be executed whenever the `watchExpression` changes. + * + * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest + * $digest()} and should return the value that will be watched. (Since + * {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the + * `watchExpression` can execute multiple times per + * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.) + * - The `listener` is called only when the value from the current `watchExpression` and the + * previous call to `watchExpression` are not equal (with the exception of the initial run, + * see below). The inequality is determined according to + * {@link angular.equals} function. To save the value of the object for later comparison, + * the {@link angular.copy} function is used. It also means that watching complex options + * will have adverse memory and performance implications. + * - The watch `listener` may change the model, which may trigger other `listener`s to fire. + * This is achieved by rerunning the watchers until no changes are detected. The rerun + * iteration limit is 10 to prevent an infinite loop deadlock. + * + * + * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called, + * you can register a `watchExpression` function with no `listener`. (Since `watchExpression` + * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a + * change is detected, be prepared for multiple calls to your listener.) + * + * After a watcher is registered with the scope, the `listener` fn is called asynchronously + * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the + * watcher. In rare cases, this is undesirable because the listener is called when the result + * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you + * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the + * listener was called due to initialization. + * + * The example below contains an illustration of using a function as your $watch listener + * + * + * # Example + *
+           // let's assume that scope was dependency injected as the $rootScope
+           var scope = $rootScope;
+           scope.name = 'misko';
+           scope.counter = 0;
+
+           expect(scope.counter).toEqual(0);
+           scope.$watch('name', function(newValue, oldValue) {
+             scope.counter = scope.counter + 1;
+           });
+           expect(scope.counter).toEqual(0);
+
+           scope.$digest();
+           // no variable change
+           expect(scope.counter).toEqual(0);
+
+           scope.name = 'adam';
+           scope.$digest();
+           expect(scope.counter).toEqual(1);
+
+
+
+           // Using a listener function
+           var food;
+           scope.foodCounter = 0;
+           expect(scope.foodCounter).toEqual(0);
+           scope.$watch(
+             // This is the listener function
+             function() { return food; },
+             // This is the change handler
+             function(newValue, oldValue) {
+               if ( newValue !== oldValue ) {
+                 // Only increment the counter if the value changed
+                 scope.foodCounter = scope.foodCounter + 1;
+               }
+             }
+           );
+           // No digest has been run so the counter will be zero
+           expect(scope.foodCounter).toEqual(0);
+
+           // Run the digest but since food has not changed cout will still be zero
+           scope.$digest();
+           expect(scope.foodCounter).toEqual(0);
+
+           // Update food and run digest.  Now the counter will increment
+           food = 'cheeseburger';
+           scope.$digest();
+           expect(scope.foodCounter).toEqual(1);
+
+       * 
+ * + * + * + * @param {(function()|string)} watchExpression Expression that is evaluated on each + * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers + * a call to the `listener`. + * + * - `string`: Evaluated as {@link guide/expression expression} + * - `function(scope)`: called with current `scope` as a parameter. + * @param {(function()|string)=} listener Callback called whenever the return value of + * the `watchExpression` changes. + * + * - `string`: Evaluated as {@link guide/expression expression} + * - `function(newValue, oldValue, scope)`: called with current and previous values as + * parameters. + * + * @param {boolean=} objectEquality Compare object for equality rather than for reference. + * @returns {function()} Returns a deregistration function for this listener. + */ + $watch: function(watchExp, listener, objectEquality) { + var scope = this, + get = compileToFn(watchExp, 'watch'), + array = scope.$$watchers, + watcher = { + fn: listener, + last: initWatchVal, + get: get, + exp: watchExp, + eq: !!objectEquality + }; + + // in the case user pass string, we need to compile it, do we really need this ? + if (!isFunction(listener)) { + var listenFn = compileToFn(listener || noop, 'listener'); + watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);}; + } + + if (typeof watchExp == 'string' && get.constant) { + var originalFn = watcher.fn; + watcher.fn = function(newVal, oldVal, scope) { + originalFn.call(this, newVal, oldVal, scope); + arrayRemove(array, watcher); + }; + } + + if (!array) { + array = scope.$$watchers = []; + } + // we use unshift since we use a while loop in $digest for speed. + // the while loop reads in reverse order. + array.unshift(watcher); + + return function() { + arrayRemove(array, watcher); + }; + }, + + + /** + * @ngdoc function + * @name ng.$rootScope.Scope#$watchCollection + * @methodOf ng.$rootScope.Scope + * @function + * + * @description + * Shallow watches the properties of an object and fires whenever any of the properties change + * (for arrays, this implies watching the array items; for object maps, this implies watching + * the properties). If a change is detected, the `listener` callback is fired. + * + * - The `obj` collection is observed via standard $watch operation and is examined on every + * call to $digest() to see if any items have been added, removed, or moved. + * - The `listener` is called whenever anything within the `obj` has changed. Examples include + * adding, removing, and moving items belonging to an object or array. + * + * + * # Example + *
+          $scope.names = ['igor', 'matias', 'misko', 'james'];
+          $scope.dataCount = 4;
+
+          $scope.$watchCollection('names', function(newNames, oldNames) {
+            $scope.dataCount = newNames.length;
+          });
+
+          expect($scope.dataCount).toEqual(4);
+          $scope.$digest();
+
+          //still at 4 ... no changes
+          expect($scope.dataCount).toEqual(4);
+
+          $scope.names.pop();
+          $scope.$digest();
+
+          //now there's been a change
+          expect($scope.dataCount).toEqual(3);
+       * 
+ * + * + * @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The + * expression value should evaluate to an object or an array which is observed on each + * {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the + * collection will trigger a call to the `listener`. + * + * @param {function(newCollection, oldCollection, scope)} listener a callback function that is + * fired with both the `newCollection` and `oldCollection` as parameters. + * The `newCollection` object is the newly modified data obtained from the `obj` expression + * and the `oldCollection` object is a copy of the former collection data. + * The `scope` refers to the current scope. + * + * @returns {function()} Returns a de-registration function for this listener. When the + * de-registration function is executed, the internal watch operation is terminated. + */ + $watchCollection: function(obj, listener) { + var self = this; + var oldValue; + var newValue; + var changeDetected = 0; + var objGetter = $parse(obj); + var internalArray = []; + var internalObject = {}; + var oldLength = 0; + + function $watchCollectionWatch() { + newValue = objGetter(self); + var newLength, key; + + if (!isObject(newValue)) { + if (oldValue !== newValue) { + oldValue = newValue; + changeDetected++; + } + } else if (isArrayLike(newValue)) { + if (oldValue !== internalArray) { + // we are transitioning from something which was not an array into array. + oldValue = internalArray; + oldLength = oldValue.length = 0; + changeDetected++; + } + + newLength = newValue.length; + + if (oldLength !== newLength) { + // if lengths do not match we need to trigger change notification + changeDetected++; + oldValue.length = oldLength = newLength; + } + // copy the items to oldValue and look for changes. + for (var i = 0; i < newLength; i++) { + if (oldValue[i] !== newValue[i]) { + changeDetected++; + oldValue[i] = newValue[i]; + } + } + } else { + if (oldValue !== internalObject) { + // we are transitioning from something which was not an object into object. + oldValue = internalObject = {}; + oldLength = 0; + changeDetected++; + } + // copy the items to oldValue and look for changes. + newLength = 0; + for (key in newValue) { + if (newValue.hasOwnProperty(key)) { + newLength++; + if (oldValue.hasOwnProperty(key)) { + if (oldValue[key] !== newValue[key]) { + changeDetected++; + oldValue[key] = newValue[key]; + } + } else { + oldLength++; + oldValue[key] = newValue[key]; + changeDetected++; + } + } + } + if (oldLength > newLength) { + // we used to have more keys, need to find them and destroy them. + changeDetected++; + for(key in oldValue) { + if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) { + oldLength--; + delete oldValue[key]; + } + } + } + } + return changeDetected; + } + + function $watchCollectionAction() { + listener(newValue, oldValue, self); + } + + return this.$watch($watchCollectionWatch, $watchCollectionAction); + }, + + /** + * @ngdoc function + * @name ng.$rootScope.Scope#$digest + * @methodOf ng.$rootScope.Scope + * @function + * + * @description + * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and + * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change + * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} + * until no more listeners are firing. This means that it is possible to get into an infinite + * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of + * iterations exceeds 10. + * + * Usually, you don't call `$digest()` directly in + * {@link ng.directive:ngController controllers} or in + * {@link ng.$compileProvider#methods_directive directives}. + * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within + * a {@link ng.$compileProvider#methods_directive directives}), which will force a `$digest()`. + * + * If you want to be notified whenever `$digest()` is called, + * you can register a `watchExpression` function with + * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`. + * + * In unit tests, you may need to call `$digest()` to simulate the scope life cycle. + * + * # Example + *
+           var scope = ...;
+           scope.name = 'misko';
+           scope.counter = 0;
+
+           expect(scope.counter).toEqual(0);
+           scope.$watch('name', function(newValue, oldValue) {
+             scope.counter = scope.counter + 1;
+           });
+           expect(scope.counter).toEqual(0);
+
+           scope.$digest();
+           // no variable change
+           expect(scope.counter).toEqual(0);
+
+           scope.name = 'adam';
+           scope.$digest();
+           expect(scope.counter).toEqual(1);
+       * 
+ * + */ + $digest: function() { + var watch, value, last, + watchers, + asyncQueue = this.$$asyncQueue, + postDigestQueue = this.$$postDigestQueue, + length, + dirty, ttl = TTL, + next, current, target = this, + watchLog = [], + logIdx, logMsg, asyncTask; + + beginPhase('$digest'); + + do { // "while dirty" loop + dirty = false; + current = target; + + while(asyncQueue.length) { + try { + asyncTask = asyncQueue.shift(); + asyncTask.scope.$eval(asyncTask.expression); + } catch (e) { + $exceptionHandler(e); + } + } + + do { // "traverse the scopes" loop + if ((watchers = current.$$watchers)) { + // process our watches + length = watchers.length; + while (length--) { + try { + watch = watchers[length]; + // Most common watches are on primitives, in which case we can short + // circuit it with === operator, only when === fails do we use .equals + if (watch && (value = watch.get(current)) !== (last = watch.last) && + !(watch.eq + ? equals(value, last) + : (typeof value == 'number' && typeof last == 'number' + && isNaN(value) && isNaN(last)))) { + dirty = true; + watch.last = watch.eq ? copy(value) : value; + watch.fn(value, ((last === initWatchVal) ? value : last), current); + if (ttl < 5) { + logIdx = 4 - ttl; + if (!watchLog[logIdx]) watchLog[logIdx] = []; + logMsg = (isFunction(watch.exp)) + ? 'fn: ' + (watch.exp.name || watch.exp.toString()) + : watch.exp; + logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last); + watchLog[logIdx].push(logMsg); + } + } + } catch (e) { + $exceptionHandler(e); + } + } + } + + // Insanity Warning: scope depth-first traversal + // yes, this code is a bit crazy, but it works and we have tests to prove it! + // this piece should be kept in sync with the traversal in $broadcast + if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) { + while(current !== target && !(next = current.$$nextSibling)) { + current = current.$parent; + } + } + } while ((current = next)); + + if(dirty && !(ttl--)) { + clearPhase(); + throw $rootScopeMinErr('infdig', + '{0} $digest() iterations reached. Aborting!\n' + + 'Watchers fired in the last 5 iterations: {1}', + TTL, toJson(watchLog)); + } + } while (dirty || asyncQueue.length); + + clearPhase(); + + while(postDigestQueue.length) { + try { + postDigestQueue.shift()(); + } catch (e) { + $exceptionHandler(e); + } + } + }, + + + /** + * @ngdoc event + * @name ng.$rootScope.Scope#$destroy + * @eventOf ng.$rootScope.Scope + * @eventType broadcast on scope being destroyed + * + * @description + * Broadcasted when a scope and its children are being destroyed. + * + * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to + * clean up DOM bindings before an element is removed from the DOM. + */ + + /** + * @ngdoc function + * @name ng.$rootScope.Scope#$destroy + * @methodOf ng.$rootScope.Scope + * @function + * + * @description + * Removes the current scope (and all of its children) from the parent scope. Removal implies + * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer + * propagate to the current scope and its children. Removal also implies that the current + * scope is eligible for garbage collection. + * + * The `$destroy()` is usually used by directives such as + * {@link ng.directive:ngRepeat ngRepeat} for managing the + * unrolling of the loop. + * + * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope. + * Application code can register a `$destroy` event handler that will give it a chance to + * perform any necessary cleanup. + * + * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to + * clean up DOM bindings before an element is removed from the DOM. + */ + $destroy: function() { + // we can't destroy the root scope or a scope that has been already destroyed + if ($rootScope == this || this.$$destroyed) return; + var parent = this.$parent; + + this.$broadcast('$destroy'); + this.$$destroyed = true; + + if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling; + if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling; + if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling; + if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling; + + // This is bogus code that works around Chrome's GC leak + // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451 + this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead = + this.$$childTail = null; + }, + + /** + * @ngdoc function + * @name ng.$rootScope.Scope#$eval + * @methodOf ng.$rootScope.Scope + * @function + * + * @description + * Executes the `expression` on the current scope and returns the result. Any exceptions in + * the expression are propagated (uncaught). This is useful when evaluating Angular + * expressions. + * + * # Example + *
+           var scope = ng.$rootScope.Scope();
+           scope.a = 1;
+           scope.b = 2;
+
+           expect(scope.$eval('a+b')).toEqual(3);
+           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
+       * 
+ * + * @param {(string|function())=} expression An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with the current `scope` parameter. + * + * @param {(object)=} locals Local variables object, useful for overriding values in scope. + * @returns {*} The result of evaluating the expression. + */ + $eval: function(expr, locals) { + return $parse(expr)(this, locals); + }, + + /** + * @ngdoc function + * @name ng.$rootScope.Scope#$evalAsync + * @methodOf ng.$rootScope.Scope + * @function + * + * @description + * Executes the expression on the current scope at a later point in time. + * + * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only + * that: + * + * - it will execute after the function that scheduled the evaluation (preferably before DOM + * rendering). + * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after + * `expression` execution. + * + * Any exceptions from the execution of the expression are forwarded to the + * {@link ng.$exceptionHandler $exceptionHandler} service. + * + * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle + * will be scheduled. However, it is encouraged to always call code that changes the model + * from within an `$apply` call. That includes code evaluated via `$evalAsync`. + * + * @param {(string|function())=} expression An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with the current `scope` parameter. + * + */ + $evalAsync: function(expr) { + // if we are outside of an $digest loop and this is the first time we are scheduling async + // task also schedule async auto-flush + if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) { + $browser.defer(function() { + if ($rootScope.$$asyncQueue.length) { + $rootScope.$digest(); + } + }); + } + + this.$$asyncQueue.push({scope: this, expression: expr}); + }, + + $$postDigest : function(fn) { + this.$$postDigestQueue.push(fn); + }, + + /** + * @ngdoc function + * @name ng.$rootScope.Scope#$apply + * @methodOf ng.$rootScope.Scope + * @function + * + * @description + * `$apply()` is used to execute an expression in angular from outside of the angular + * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries). + * Because we are calling into the angular framework we need to perform proper scope life + * cycle of {@link ng.$exceptionHandler exception handling}, + * {@link ng.$rootScope.Scope#$digest executing watches}. + * + * ## Life cycle + * + * # Pseudo-Code of `$apply()` + *
+           function $apply(expr) {
+             try {
+               return $eval(expr);
+             } catch (e) {
+               $exceptionHandler(e);
+             } finally {
+               $root.$digest();
+             }
+           }
+       * 
+ * + * + * Scope's `$apply()` method transitions through the following stages: + * + * 1. The {@link guide/expression expression} is executed using the + * {@link ng.$rootScope.Scope#$eval $eval()} method. + * 2. Any exceptions from the execution of the expression are forwarded to the + * {@link ng.$exceptionHandler $exceptionHandler} service. + * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the + * expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method. + * + * + * @param {(string|function())=} exp An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with current `scope` parameter. + * + * @returns {*} The result of evaluating the expression. + */ + $apply: function(expr) { + try { + beginPhase('$apply'); + return this.$eval(expr); + } catch (e) { + $exceptionHandler(e); + } finally { + clearPhase(); + try { + $rootScope.$digest(); + } catch (e) { + $exceptionHandler(e); + throw e; + } + } + }, + + /** + * @ngdoc function + * @name ng.$rootScope.Scope#$on + * @methodOf ng.$rootScope.Scope + * @function + * + * @description + * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for + * discussion of event life cycle. + * + * The event listener function format is: `function(event, args...)`. The `event` object + * passed into the listener has the following attributes: + * + * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or + * `$broadcast`-ed. + * - `currentScope` - `{Scope}`: the current scope which is handling the event. + * - `name` - `{string}`: name of the event. + * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel + * further event propagation (available only for events that were `$emit`-ed). + * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag + * to true. + * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called. + * + * @param {string} name Event name to listen on. + * @param {function(event, args...)} listener Function to call when the event is emitted. + * @returns {function()} Returns a deregistration function for this listener. + */ + $on: function(name, listener) { + var namedListeners = this.$$listeners[name]; + if (!namedListeners) { + this.$$listeners[name] = namedListeners = []; + } + namedListeners.push(listener); + + return function() { + namedListeners[indexOf(namedListeners, listener)] = null; + }; + }, + + + /** + * @ngdoc function + * @name ng.$rootScope.Scope#$emit + * @methodOf ng.$rootScope.Scope + * @function + * + * @description + * Dispatches an event `name` upwards through the scope hierarchy notifying the + * registered {@link ng.$rootScope.Scope#$on} listeners. + * + * The event life cycle starts at the scope on which `$emit` was called. All + * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get + * notified. Afterwards, the event traverses upwards toward the root scope and calls all + * registered listeners along the way. The event will stop propagating if one of the listeners + * cancels it. + * + * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed + * onto the {@link ng.$exceptionHandler $exceptionHandler} service. + * + * @param {string} name Event name to emit. + * @param {...*} args Optional set of arguments which will be passed onto the event listeners. + * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}). + */ + $emit: function(name, args) { + var empty = [], + namedListeners, + scope = this, + stopPropagation = false, + event = { + name: name, + targetScope: scope, + stopPropagation: function() {stopPropagation = true;}, + preventDefault: function() { + event.defaultPrevented = true; + }, + defaultPrevented: false + }, + listenerArgs = concat([event], arguments, 1), + i, length; + + do { + namedListeners = scope.$$listeners[name] || empty; + event.currentScope = scope; + for (i=0, length=namedListeners.length; i= 8 ) { + normalizedVal = urlResolve(uri).href; + if (normalizedVal !== '' && !normalizedVal.match(regex)) { + return 'unsafe:'+normalizedVal; + } + } + return uri; + }; + }; +} + +var $sceMinErr = minErr('$sce'); + +var SCE_CONTEXTS = { + HTML: 'html', + CSS: 'css', + URL: 'url', + // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a + // url. (e.g. ng-include, script src, templateUrl) + RESOURCE_URL: 'resourceUrl', + JS: 'js' +}; + +// Helper functions follow. + +// Copied from: +// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962 +// Prereq: s is a string. +function escapeForRegexp(s) { + return s.replace(/([-()\[\]{}+?*.$\^|,:# -1) { + throw $sceMinErr('iwcard', + 'Illegal sequence *** in string matcher. String: {0}', matcher); + } + matcher = escapeForRegexp(matcher). + replace('\\*\\*', '.*'). + replace('\\*', '[^:/.?&;]*'); + return new RegExp('^' + matcher + '$'); + } else if (isRegExp(matcher)) { + // The only other type of matcher allowed is a Regexp. + // Match entire URL / disallow partial matches. + // Flags are reset (i.e. no global, ignoreCase or multiline) + return new RegExp('^' + matcher.source + '$'); + } else { + throw $sceMinErr('imatcher', + 'Matchers may only be "self", string patterns or RegExp objects'); + } +} + + +function adjustMatchers(matchers) { + var adjustedMatchers = []; + if (isDefined(matchers)) { + forEach(matchers, function(matcher) { + adjustedMatchers.push(adjustMatcher(matcher)); + }); + } + return adjustedMatchers; +} + + +/** + * @ngdoc service + * @name ng.$sceDelegate + * @function + * + * @description + * + * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict + * Contextual Escaping (SCE)} services to AngularJS. + * + * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of + * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS. This is + * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to + * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things + * work because `$sce` delegates to `$sceDelegate` for these operations. + * + * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service. + * + * The default instance of `$sceDelegate` should work out of the box with little pain. While you + * can override it completely to change the behavior of `$sce`, the common case would + * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting + * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as + * templates. Refer {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist + * $sceDelegateProvider.resourceUrlWhitelist} and {@link + * ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} + */ + +/** + * @ngdoc object + * @name ng.$sceDelegateProvider + * @description + * + * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate + * $sceDelegate} service. This allows one to get/set the whitelists and blacklists used to ensure + * that the URLs used for sourcing Angular templates are safe. Refer {@link + * ng.$sceDelegateProvider#methods_resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and + * {@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} + * + * For the general details about this service in Angular, read the main page for {@link ng.$sce + * Strict Contextual Escaping (SCE)}. + * + * **Example**: Consider the following case. + * + * - your app is hosted at url `http://myapp.example.com/` + * - but some of your templates are hosted on other domains you control such as + * `http://srv01.assets.example.com/`, `http://srv02.assets.example.com/`, etc. + * - and you have an open redirect at `http://myapp.example.com/clickThru?...`. + * + * Here is what a secure configuration for this scenario might look like: + * + *
+ *    angular.module('myApp', []).config(function($sceDelegateProvider) {
+ *      $sceDelegateProvider.resourceUrlWhitelist([
+ *        // Allow same origin resource loads.
+ *        'self',
+ *        // Allow loading from our assets domain.  Notice the difference between * and **.
+ *        'http://srv*.assets.example.com/**']);
+ *
+ *      // The blacklist overrides the whitelist so the open redirect here is blocked.
+ *      $sceDelegateProvider.resourceUrlBlacklist([
+ *        'http://myapp.example.com/clickThru**']);
+ *      });
+ * 
+ */ + +function $SceDelegateProvider() { + this.SCE_CONTEXTS = SCE_CONTEXTS; + + // Resource URLs can also be trusted by policy. + var resourceUrlWhitelist = ['self'], + resourceUrlBlacklist = []; + + /** + * @ngdoc function + * @name ng.sceDelegateProvider#resourceUrlWhitelist + * @methodOf ng.$sceDelegateProvider + * @function + * + * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value + * provided. This must be an array or null. A snapshot of this array is used so further + * changes to the array are ignored. + * + * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items + * allowed in this array. + * + * Note: **an empty whitelist array will block all URLs**! + * + * @return {Array} the currently set whitelist array. + * + * The **default value** when no whitelist has been explicitly set is `['self']` allowing only + * same origin resource requests. + * + * @description + * Sets/Gets the whitelist of trusted resource URLs. + */ + this.resourceUrlWhitelist = function (value) { + if (arguments.length) { + resourceUrlWhitelist = adjustMatchers(value); + } + return resourceUrlWhitelist; + }; + + /** + * @ngdoc function + * @name ng.sceDelegateProvider#resourceUrlBlacklist + * @methodOf ng.$sceDelegateProvider + * @function + * + * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value + * provided. This must be an array or null. A snapshot of this array is used so further + * changes to the array are ignored. + * + * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items + * allowed in this array. + * + * The typical usage for the blacklist is to **block + * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as + * these would otherwise be trusted but actually return content from the redirected domain. + * + * Finally, **the blacklist overrides the whitelist** and has the final say. + * + * @return {Array} the currently set blacklist array. + * + * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there + * is no blacklist.) + * + * @description + * Sets/Gets the blacklist of trusted resource URLs. + */ + + this.resourceUrlBlacklist = function (value) { + if (arguments.length) { + resourceUrlBlacklist = adjustMatchers(value); + } + return resourceUrlBlacklist; + }; + + this.$get = ['$injector', function($injector) { + + var htmlSanitizer = function htmlSanitizer(html) { + throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); + }; + + if ($injector.has('$sanitize')) { + htmlSanitizer = $injector.get('$sanitize'); + } + + + function matchUrl(matcher, parsedUrl) { + if (matcher === 'self') { + return urlIsSameOrigin(parsedUrl); + } else { + // definitely a regex. See adjustMatchers() + return !!matcher.exec(parsedUrl.href); + } + } + + function isResourceUrlAllowedByPolicy(url) { + var parsedUrl = urlResolve(url.toString()); + var i, n, allowed = false; + // Ensure that at least one item from the whitelist allows this url. + for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) { + if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) { + allowed = true; + break; + } + } + if (allowed) { + // Ensure that no item from the blacklist blocked this url. + for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) { + if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) { + allowed = false; + break; + } + } + } + return allowed; + } + + function generateHolderType(Base) { + var holderType = function TrustedValueHolderType(trustedValue) { + this.$$unwrapTrustedValue = function() { + return trustedValue; + }; + }; + if (Base) { + holderType.prototype = new Base(); + } + holderType.prototype.valueOf = function sceValueOf() { + return this.$$unwrapTrustedValue(); + }; + holderType.prototype.toString = function sceToString() { + return this.$$unwrapTrustedValue().toString(); + }; + return holderType; + } + + var trustedValueHolderBase = generateHolderType(), + byType = {}; + + byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]); + + /** + * @ngdoc method + * @name ng.$sceDelegate#trustAs + * @methodOf ng.$sceDelegate + * + * @description + * Returns an object that is trusted by angular for use in specified strict + * contextual escaping contexts (such as ng-html-bind-unsafe, ng-include, any src + * attribute interpolation, any dom event binding attribute interpolation + * such as for onclick, etc.) that uses the provided value. + * See {@link ng.$sce $sce} for enabling strict contextual escaping. + * + * @param {string} type The kind of context in which this value is safe for use. e.g. url, + * resourceUrl, html, js and css. + * @param {*} value The value that that should be considered trusted/safe. + * @returns {*} A value that can be used to stand in for the provided `value` in places + * where Angular expects a $sce.trustAs() return value. + */ + function trustAs(type, trustedValue) { + var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null); + if (!Constructor) { + throw $sceMinErr('icontext', + 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}', + type, trustedValue); + } + if (trustedValue === null || trustedValue === undefined || trustedValue === '') { + return trustedValue; + } + // All the current contexts in SCE_CONTEXTS happen to be strings. In order to avoid trusting + // mutable objects, we ensure here that the value passed in is actually a string. + if (typeof trustedValue !== 'string') { + throw $sceMinErr('itype', + 'Attempted to trust a non-string value in a content requiring a string: Context: {0}', + type); + } + return new Constructor(trustedValue); + } + + /** + * @ngdoc method + * @name ng.$sceDelegate#valueOf + * @methodOf ng.$sceDelegate + * + * @description + * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#methods_trustAs + * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link + * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}. + * + * If the passed parameter is not a value that had been returned by {@link + * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}, returns it as-is. + * + * @param {*} value The result of a prior {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`} + * call or anything else. + * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#methods_trustAs + * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns + * `value` unchanged. + */ + function valueOf(maybeTrusted) { + if (maybeTrusted instanceof trustedValueHolderBase) { + return maybeTrusted.$$unwrapTrustedValue(); + } else { + return maybeTrusted; + } + } + + /** + * @ngdoc method + * @name ng.$sceDelegate#getTrusted + * @methodOf ng.$sceDelegate + * + * @description + * Takes the result of a {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`} call and + * returns the originally supplied value if the queried context type is a supertype of the + * created type. If this condition isn't satisfied, throws an exception. + * + * @param {string} type The kind of context in which this value is to be used. + * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#methods_trustAs + * `$sceDelegate.trustAs`} call. + * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#methods_trustAs + * `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception. + */ + function getTrusted(type, maybeTrusted) { + if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') { + return maybeTrusted; + } + var constructor = (byType.hasOwnProperty(type) ? byType[type] : null); + if (constructor && maybeTrusted instanceof constructor) { + return maybeTrusted.$$unwrapTrustedValue(); + } + // If we get here, then we may only take one of two actions. + // 1. sanitize the value for the requested type, or + // 2. throw an exception. + if (type === SCE_CONTEXTS.RESOURCE_URL) { + if (isResourceUrlAllowedByPolicy(maybeTrusted)) { + return maybeTrusted; + } else { + throw $sceMinErr('insecurl', + 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}', + maybeTrusted.toString()); + } + } else if (type === SCE_CONTEXTS.HTML) { + return htmlSanitizer(maybeTrusted); + } + throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); + } + + return { trustAs: trustAs, + getTrusted: getTrusted, + valueOf: valueOf }; + }]; +} + + +/** + * @ngdoc object + * @name ng.$sceProvider + * @description + * + * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service. + * - enable/disable Strict Contextual Escaping (SCE) in a module + * - override the default implementation with a custom delegate + * + * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}. + */ + +/* jshint maxlen: false*/ + +/** + * @ngdoc service + * @name ng.$sce + * @function + * + * @description + * + * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS. + * + * # Strict Contextual Escaping + * + * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain + * contexts to result in a value that is marked as safe to use for that context. One example of + * such a context is binding arbitrary html controlled by the user via `ng-bind-html`. We refer + * to these contexts as privileged or SCE contexts. + * + * As of version 1.2, Angular ships with SCE enabled by default. + * + * Note: When enabled (the default), IE8 in quirks mode is not supported. In this mode, IE8 allows + * one to execute arbitrary javascript by the use of the expression() syntax. Refer + * to learn more about them. + * You can ensure your document is in standards mode and not quirks mode by adding `` + * to the top of your HTML document. + * + * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for + * security vulnerabilities such as XSS, clickjacking, etc. a lot easier. + * + * Here's an example of a binding in a privileged context: + * + *
+ *     
+ *     
+ *
+ * + * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE + * disabled, this application allows the user to render arbitrary HTML into the DIV. + * In a more realistic example, one may be rendering user comments, blog articles, etc. via + * bindings. (HTML is just one example of a context where rendering user controlled input creates + * security vulnerabilities.) + * + * For the case of HTML, you might use a library, either on the client side, or on the server side, + * to sanitize unsafe HTML before binding to the value and rendering it in the document. + * + * How would you ensure that every place that used these types of bindings was bound to a value that + * was sanitized by your library (or returned as safe for rendering by your server?) How can you + * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some + * properties/fields and forgot to update the binding to the sanitized value? + * + * To be secure by default, you want to ensure that any such bindings are disallowed unless you can + * determine that something explicitly says it's safe to use a value for binding in that + * context. You can then audit your code (a simple grep would do) to ensure that this is only done + * for those values that you can easily tell are safe - because they were received from your server, + * sanitized by your library, etc. You can organize your codebase to help with this - perhaps + * allowing only the files in a specific directory to do this. Ensuring that the internal API + * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task. + * + * In the case of AngularJS' SCE service, one uses {@link ng.$sce#methods_trustAs $sce.trustAs} + * (and shorthand methods such as {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}, etc.) to + * obtain values that will be accepted by SCE / privileged contexts. + * + * + * ## How does it work? + * + * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#methods_getTrusted + * $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link + * ng.$sce#methods_parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the + * {@link ng.$sce#methods_getTrusted $sce.getTrusted} behind the scenes on non-constant literals. + * + * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link + * ng.$sce#methods_parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly + * simplified): + * + *
+ *   var ngBindHtmlDirective = ['$sce', function($sce) {
+ *     return function(scope, element, attr) {
+ *       scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
+ *         element.html(value || '');
+ *       });
+ *     };
+ *   }];
+ * 
+ * + * ## Impact on loading templates + * + * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as + * `templateUrl`'s specified by {@link guide/directive directives}. + * + * By default, Angular only loads templates from the same domain and protocol as the application + * document. This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl + * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or + * protocols, you may either either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist + * them} or {@link ng.$sce#methods_trustAsResourceUrl wrap it} into a trusted value. + * + * *Please note*: + * The browser's + * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest + * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing (CORS)} + * policy apply in addition to this and may further restrict whether the template is successfully + * loaded. This means that without the right CORS policy, loading templates from a different domain + * won't work on all browsers. Also, loading templates from `file://` URL does not work on some + * browsers. + * + * ## This feels like too much overhead for the developer? + * + * It's important to remember that SCE only applies to interpolation expressions. + * + * If your expressions are constant literals, they're automatically trusted and you don't need to + * call `$sce.trustAs` on them. (e.g. + * `
`) just works. + * + * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them + * through {@link ng.$sce#methods_getTrusted $sce.getTrusted}. SCE doesn't play a role here. + * + * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load + * templates in `ng-include` from your application's domain without having to even know about SCE. + * It blocks loading templates from other domains or loading templates over http from an https + * served document. You can change these by setting your own custom {@link + * ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelists} and {@link + * ng.$sceDelegateProvider#methods_resourceUrlBlacklist blacklists} for matching such URLs. + * + * This significantly reduces the overhead. It is far easier to pay the small overhead and have an + * application that's secure and can be audited to verify that with much more ease than bolting + * security onto an application later. + * + * + * ## What trusted context types are supported? + * + * | Context | Notes | + * |---------------------|----------------| + * | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. | + * | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. | + * | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`
Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. | + * | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. | + * + * ## Format of items in {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist Blacklist}
+ * + * Each element in these arrays must be one of the following: + * + * - **'self'** + * - The special **string**, `'self'`, can be used to match against all URLs of the **same + * domain** as the application document using the **same protocol**. + * - **String** (except the special value `'self'`) + * - The string is matched against the full *normalized / absolute URL* of the resource + * being tested (substring matches are not good enough.) + * - There are exactly **two wildcard sequences** - `*` and `**`. All other characters + * match themselves. + * - `*`: matches zero or more occurances of any character other than one of the following 6 + * characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'. It's a useful wildcard for use + * in a whitelist. + * - `**`: matches zero or more occurances of *any* character. As such, it's not + * not appropriate to use in for a scheme, domain, etc. as it would match too much. (e.g. + * http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might + * not have been the intention.) It's usage at the very end of the path is ok. (e.g. + * http://foo.example.com/templates/**). + * - **RegExp** (*see caveat below*) + * - *Caveat*: While regular expressions are powerful and offer great flexibility, their syntax + * (and all the inevitable escaping) makes them *harder to maintain*. It's easy to + * accidentally introduce a bug when one updates a complex expression (imho, all regexes should + * have good test coverage.). For instance, the use of `.` in the regex is correct only in a + * small number of cases. A `.` character in the regex used when matching the scheme or a + * subdomain could be matched against a `:` or literal `.` that was likely not intended. It + * is highly recommended to use the string patterns and only fall back to regular expressions + * if they as a last resort. + * - The regular expression must be an instance of RegExp (i.e. not a string.) It is + * matched against the **entire** *normalized / absolute URL* of the resource being tested + * (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags + * present on the RegExp (such as multiline, global, ignoreCase) are ignored. + * - If you are generating your Javascript from some other templating engine (not + * recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)), + * remember to escape your regular expression (and be aware that you might need more than + * one level of escaping depending on your templating engine and the way you interpolated + * the value.) Do make use of your platform's escaping mechanism as it might be good + * enough before coding your own. e.g. Ruby has + * [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape) + * and Python has [re.escape](http://docs.python.org/library/re.html#re.escape). + * Javascript lacks a similar built in function for escaping. Take a look at Google + * Closure library's [goog.string.regExpEscape(s)]( + * http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962). + * + * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example. + * + * ## Show me an example using SCE. + * + * @example + + +
+

+ User comments
+ By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when + $sanitize is available. If $sanitize isn't available, this results in an error instead of an + exploit. +
+
+ {{userComment.name}}: + +
+
+
+
+
+ + + var mySceApp = angular.module('mySceApp', ['ngSanitize']); + + mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) { + var self = this; + $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) { + self.userComments = userComments; + }); + self.explicitlyTrustedHtml = $sce.trustAsHtml( + 'Hover over this text.'); + }); + + + +[ + { "name": "Alice", + "htmlComment": + "Is anyone reading this?" + }, + { "name": "Bob", + "htmlComment": "Yes! Am I the only other one?" + } +] + + + + describe('SCE doc demo', function() { + it('should sanitize untrusted values', function() { + expect(element('.htmlComment').html()).toBe('Is anyone reading this?'); + }); + it('should NOT sanitize explicitly trusted values', function() { + expect(element('#explicitlyTrustedHtml').html()).toBe( + 'Hover over this text.'); + }); + }); + +
+ * + * + * + * ## Can I disable SCE completely? + * + * Yes, you can. However, this is strongly discouraged. SCE gives you a lot of security benefits + * for little coding overhead. It will be much harder to take an SCE disabled application and + * either secure it on your own or enable SCE at a later stage. It might make sense to disable SCE + * for cases where you have a lot of existing code that was written before SCE was introduced and + * you're migrating them a module at a time. + * + * That said, here's how you can completely disable SCE: + * + *
+ *   angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
+ *     // Completely disable SCE.  For demonstration purposes only!
+ *     // Do not use in new projects.
+ *     $sceProvider.enabled(false);
+ *   });
+ * 
+ * + */ +/* jshint maxlen: 100 */ + +function $SceProvider() { + var enabled = true; + + /** + * @ngdoc function + * @name ng.sceProvider#enabled + * @methodOf ng.$sceProvider + * @function + * + * @param {boolean=} value If provided, then enables/disables SCE. + * @return {boolean} true if SCE is enabled, false otherwise. + * + * @description + * Enables/disables SCE and returns the current value. + */ + this.enabled = function (value) { + if (arguments.length) { + enabled = !!value; + } + return enabled; + }; + + + /* Design notes on the default implementation for SCE. + * + * The API contract for the SCE delegate + * ------------------------------------- + * The SCE delegate object must provide the following 3 methods: + * + * - trustAs(contextEnum, value) + * This method is used to tell the SCE service that the provided value is OK to use in the + * contexts specified by contextEnum. It must return an object that will be accepted by + * getTrusted() for a compatible contextEnum and return this value. + * + * - valueOf(value) + * For values that were not produced by trustAs(), return them as is. For values that were + * produced by trustAs(), return the corresponding input value to trustAs. Basically, if + * trustAs is wrapping the given values into some type, this operation unwraps it when given + * such a value. + * + * - getTrusted(contextEnum, value) + * This function should return the a value that is safe to use in the context specified by + * contextEnum or throw and exception otherwise. + * + * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be + * opaque or wrapped in some holder object. That happens to be an implementation detail. For + * instance, an implementation could maintain a registry of all trusted objects by context. In + * such a case, trustAs() would return the same object that was passed in. getTrusted() would + * return the same object passed in if it was found in the registry under a compatible context or + * throw an exception otherwise. An implementation might only wrap values some of the time based + * on some criteria. getTrusted() might return a value and not throw an exception for special + * constants or objects even if not wrapped. All such implementations fulfill this contract. + * + * + * A note on the inheritance model for SCE contexts + * ------------------------------------------------ + * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types. This + * is purely an implementation details. + * + * The contract is simply this: + * + * getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value) + * will also succeed. + * + * Inheritance happens to capture this in a natural way. In some future, we + * may not use inheritance anymore. That is OK because no code outside of + * sce.js and sceSpecs.js would need to be aware of this detail. + */ + + this.$get = ['$parse', '$sniffer', '$sceDelegate', function( + $parse, $sniffer, $sceDelegate) { + // Prereq: Ensure that we're not running in IE8 quirks mode. In that mode, IE allows + // the "expression(javascript expression)" syntax which is insecure. + if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) { + throw $sceMinErr('iequirks', + 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' + + 'mode. You can fix this by adding the text to the top of your HTML ' + + 'document. See http://docs.angularjs.org/api/ng.$sce for more information.'); + } + + var sce = copy(SCE_CONTEXTS); + + /** + * @ngdoc function + * @name ng.sce#isEnabled + * @methodOf ng.$sce + * @function + * + * @return {Boolean} true if SCE is enabled, false otherwise. If you want to set the value, you + * have to do it at module config time on {@link ng.$sceProvider $sceProvider}. + * + * @description + * Returns a boolean indicating if SCE is enabled. + */ + sce.isEnabled = function () { + return enabled; + }; + sce.trustAs = $sceDelegate.trustAs; + sce.getTrusted = $sceDelegate.getTrusted; + sce.valueOf = $sceDelegate.valueOf; + + if (!enabled) { + sce.trustAs = sce.getTrusted = function(type, value) { return value; }; + sce.valueOf = identity; + } + + /** + * @ngdoc method + * @name ng.$sce#parse + * @methodOf ng.$sce + * + * @description + * Converts Angular {@link guide/expression expression} into a function. This is like {@link + * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it + * wraps the expression in a call to {@link ng.$sce#methods_getTrusted $sce.getTrusted(*type*, + * *result*)} + * + * @param {string} type The kind of SCE context in which this result will be used. + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + sce.parseAs = function sceParseAs(type, expr) { + var parsed = $parse(expr); + if (parsed.literal && parsed.constant) { + return parsed; + } else { + return function sceParseAsTrusted(self, locals) { + return sce.getTrusted(type, parsed(self, locals)); + }; + } + }; + + /** + * @ngdoc method + * @name ng.$sce#trustAs + * @methodOf ng.$sce + * + * @description + * Delegates to {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}. As such, + * returns an objectthat is trusted by angular for use in specified strict contextual + * escaping contexts (such as ng-html-bind-unsafe, ng-include, any src attribute + * interpolation, any dom event binding attribute interpolation such as for onclick, etc.) + * that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual + * escaping. + * + * @param {string} type The kind of context in which this value is safe for use. e.g. url, + * resource_url, html, js and css. + * @param {*} value The value that that should be considered trusted/safe. + * @returns {*} A value that can be used to stand in for the provided `value` in places + * where Angular expects a $sce.trustAs() return value. + */ + + /** + * @ngdoc method + * @name ng.$sce#trustAsHtml + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.trustAsHtml(value)` → + * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.HTML, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedHtml + * $sce.getTrustedHtml(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the + * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name ng.$sce#trustAsUrl + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.trustAsUrl(value)` → + * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.URL, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedUrl + * $sce.getTrustedUrl(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the + * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name ng.$sce#trustAsResourceUrl + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.trustAsResourceUrl(value)` → + * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedResourceUrl + * $sce.getTrustedResourceUrl(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the return + * value of {@link ng.$sce#methods_trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name ng.$sce#trustAsJs + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.trustAsJs(value)` → + * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.JS, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedJs + * $sce.getTrustedJs(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the + * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name ng.$sce#getTrusted + * @methodOf ng.$sce + * + * @description + * Delegates to {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted`}. As such, + * takes the result of a {@link ng.$sce#methods_trustAs `$sce.trustAs`}() call and returns the + * originally supplied value if the queried context type is a supertype of the created type. + * If this condition isn't satisfied, throws an exception. + * + * @param {string} type The kind of context in which this value is to be used. + * @param {*} maybeTrusted The result of a prior {@link ng.$sce#methods_trustAs `$sce.trustAs`} + * call. + * @returns {*} The value the was originally provided to + * {@link ng.$sce#methods_trustAs `$sce.trustAs`} if valid in this context. + * Otherwise, throws an exception. + */ + + /** + * @ngdoc method + * @name ng.$sce#getTrustedHtml + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.getTrustedHtml(value)` → + * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)` + */ + + /** + * @ngdoc method + * @name ng.$sce#getTrustedCss + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.getTrustedCss(value)` → + * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)` + */ + + /** + * @ngdoc method + * @name ng.$sce#getTrustedUrl + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.getTrustedUrl(value)` → + * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.URL, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)` + */ + + /** + * @ngdoc method + * @name ng.$sce#getTrustedResourceUrl + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.getTrustedResourceUrl(value)` → + * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`} + * + * @param {*} value The value to pass to `$sceDelegate.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)` + */ + + /** + * @ngdoc method + * @name ng.$sce#getTrustedJs + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.getTrustedJs(value)` → + * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.JS, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)` + */ + + /** + * @ngdoc method + * @name ng.$sce#parseAsHtml + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.parseAsHtml(expression string)` → + * {@link ng.$sce#methods_parse `$sce.parseAs($sce.HTML, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name ng.$sce#parseAsCss + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.parseAsCss(value)` → + * {@link ng.$sce#methods_parse `$sce.parseAs($sce.CSS, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name ng.$sce#parseAsUrl + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.parseAsUrl(value)` → + * {@link ng.$sce#methods_parse `$sce.parseAs($sce.URL, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name ng.$sce#parseAsResourceUrl + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.parseAsResourceUrl(value)` → + * {@link ng.$sce#methods_parse `$sce.parseAs($sce.RESOURCE_URL, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name ng.$sce#parseAsJs + * @methodOf ng.$sce + * + * @description + * Shorthand method. `$sce.parseAsJs(value)` → + * {@link ng.$sce#methods_parse `$sce.parseAs($sce.JS, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + // Shorthand delegations. + var parse = sce.parseAs, + getTrusted = sce.getTrusted, + trustAs = sce.trustAs; + + forEach(SCE_CONTEXTS, function (enumValue, name) { + var lName = lowercase(name); + sce[camelCase("parse_as_" + lName)] = function (expr) { + return parse(enumValue, expr); + }; + sce[camelCase("get_trusted_" + lName)] = function (value) { + return getTrusted(enumValue, value); + }; + sce[camelCase("trust_as_" + lName)] = function (value) { + return trustAs(enumValue, value); + }; + }); + + return sce; + }]; +} + +/** + * !!! This is an undocumented "private" service !!! + * + * @name ng.$sniffer + * @requires $window + * @requires $document + * + * @property {boolean} history Does the browser support html5 history api ? + * @property {boolean} hashchange Does the browser support hashchange event ? + * @property {boolean} transitions Does the browser support CSS transition events ? + * @property {boolean} animations Does the browser support CSS animation events ? + * + * @description + * This is very simple implementation of testing browser's features. + */ +function $SnifferProvider() { + this.$get = ['$window', '$document', function($window, $document) { + var eventSupport = {}, + android = + int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]), + boxee = /Boxee/i.test(($window.navigator || {}).userAgent), + document = $document[0] || {}, + documentMode = document.documentMode, + vendorPrefix, + vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/, + bodyStyle = document.body && document.body.style, + transitions = false, + animations = false, + match; + + if (bodyStyle) { + for(var prop in bodyStyle) { + if(match = vendorRegex.exec(prop)) { + vendorPrefix = match[0]; + vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1); + break; + } + } + + if(!vendorPrefix) { + vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit'; + } + + transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle)); + animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle)); + + if (android && (!transitions||!animations)) { + transitions = isString(document.body.style.webkitTransition); + animations = isString(document.body.style.webkitAnimation); + } + } + + + return { + // Android has history.pushState, but it does not update location correctly + // so let's not use the history API at all. + // http://code.google.com/p/android/issues/detail?id=17471 + // https://github.com/angular/angular.js/issues/904 + + // older webit browser (533.9) on Boxee box has exactly the same problem as Android has + // so let's not use the history API also + // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined + // jshint -W018 + history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee), + // jshint +W018 + hashchange: 'onhashchange' in $window && + // IE8 compatible mode lies + (!documentMode || documentMode > 7), + hasEvent: function(event) { + // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have + // it. In particular the event is not fired when backspace or delete key are pressed or + // when cut operation is performed. + if (event == 'input' && msie == 9) return false; + + if (isUndefined(eventSupport[event])) { + var divElm = document.createElement('div'); + eventSupport[event] = 'on' + event in divElm; + } + + return eventSupport[event]; + }, + csp: csp(), + vendorPrefix: vendorPrefix, + transitions : transitions, + animations : animations, + msie : msie, + msieDocumentMode: documentMode + }; + }]; +} + +function $TimeoutProvider() { + this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler', + function($rootScope, $browser, $q, $exceptionHandler) { + var deferreds = {}; + + + /** + * @ngdoc function + * @name ng.$timeout + * @requires $browser + * + * @description + * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch + * block and delegates any exceptions to + * {@link ng.$exceptionHandler $exceptionHandler} service. + * + * The return value of registering a timeout function is a promise, which will be resolved when + * the timeout is reached and the timeout function is executed. + * + * To cancel a timeout request, call `$timeout.cancel(promise)`. + * + * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to + * synchronously flush the queue of deferred functions. + * + * @param {function()} fn A function, whose execution should be delayed. + * @param {number=} [delay=0] Delay in milliseconds. + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise + * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block. + * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this + * promise will be resolved with is the return value of the `fn` function. + * + * @example + + + + +
+
+ Date format:
+ Current time is: +
+ Blood 1 : {{blood_1}} + Blood 2 : {{blood_2}} + + + +
+
+ +
+
+ */ + function timeout(fn, delay, invokeApply) { + var deferred = $q.defer(), + promise = deferred.promise, + skipApply = (isDefined(invokeApply) && !invokeApply), + timeoutId; + + timeoutId = $browser.defer(function() { + try { + deferred.resolve(fn()); + } catch(e) { + deferred.reject(e); + $exceptionHandler(e); + } + finally { + delete deferreds[promise.$$timeoutId]; + } + + if (!skipApply) $rootScope.$apply(); + }, delay); + + promise.$$timeoutId = timeoutId; + deferreds[timeoutId] = deferred; + + return promise; + } + + + /** + * @ngdoc function + * @name ng.$timeout#cancel + * @methodOf ng.$timeout + * + * @description + * Cancels a task associated with the `promise`. As a result of this, the promise will be + * resolved with a rejection. + * + * @param {Promise=} promise Promise returned by the `$timeout` function. + * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully + * canceled. + */ + timeout.cancel = function(promise) { + if (promise && promise.$$timeoutId in deferreds) { + deferreds[promise.$$timeoutId].reject('canceled'); + delete deferreds[promise.$$timeoutId]; + return $browser.defer.cancel(promise.$$timeoutId); + } + return false; + }; + + return timeout; + }]; +} + +// NOTE: The usage of window and document instead of $window and $document here is +// deliberate. This service depends on the specific behavior of anchor nodes created by the +// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and +// cause us to break tests. In addition, when the browser resolves a URL for XHR, it +// doesn't know about mocked locations and resolves URLs to the real document - which is +// exactly the behavior needed here. There is little value is mocking these out for this +// service. +var urlParsingNode = document.createElement("a"); +var originUrl = urlResolve(window.location.href, true); + + +/** + * + * Implementation Notes for non-IE browsers + * ---------------------------------------- + * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM, + * results both in the normalizing and parsing of the URL. Normalizing means that a relative + * URL will be resolved into an absolute URL in the context of the application document. + * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related + * properties are all populated to reflect the normalized URL. This approach has wide + * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc. See + * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html + * + * Implementation Notes for IE + * --------------------------- + * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other + * browsers. However, the parsed components will not be set if the URL assigned did not specify + * them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We + * work around that by performing the parsing in a 2nd step by taking a previously normalized + * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the + * properties such as protocol, hostname, port, etc. + * + * IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one + * uses the inner HTML approach to assign the URL as part of an HTML snippet - + * http://stackoverflow.com/a/472729) However, setting img[src] does normalize the URL. + * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception. + * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that + * method and IE < 8 is unsupported. + * + * References: + * http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement + * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html + * http://url.spec.whatwg.org/#urlutils + * https://github.com/angular/angular.js/pull/2902 + * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/ + * + * @function + * @param {string} url The URL to be parsed. + * @description Normalizes and parses a URL. + * @returns {object} Returns the normalized URL as a dictionary. + * + * | member name | Description | + * |---------------|----------------| + * | href | A normalized version of the provided URL if it was not an absolute URL | + * | protocol | The protocol including the trailing colon | + * | host | The host and port (if the port is non-default) of the normalizedUrl | + * | search | The search params, minus the question mark | + * | hash | The hash string, minus the hash symbol + * | hostname | The hostname + * | port | The port, without ":" + * | pathname | The pathname, beginning with "/" + * + */ +function urlResolve(url, base) { + var href = url; + + if (msie) { + // Normalize before parse. Refer Implementation Notes on why this is + // done in two steps on IE. + urlParsingNode.setAttribute("href", href); + href = urlParsingNode.href; + } + + urlParsingNode.setAttribute('href', href); + + // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils + return { + href: urlParsingNode.href, + protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', + host: urlParsingNode.host, + search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', + hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', + hostname: urlParsingNode.hostname, + port: urlParsingNode.port, + pathname: (urlParsingNode.pathname.charAt(0) === '/') + ? urlParsingNode.pathname + : '/' + urlParsingNode.pathname + }; +} + +/** + * Parse a request URL and determine whether this is a same-origin request as the application document. + * + * @param {string|object} requestUrl The url of the request as a string that will be resolved + * or a parsed URL object. + * @returns {boolean} Whether the request is for the same origin as the application document. + */ +function urlIsSameOrigin(requestUrl) { + var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl; + return (parsed.protocol === originUrl.protocol && + parsed.host === originUrl.host); +} + +/** + * @ngdoc object + * @name ng.$window + * + * @description + * A reference to the browser's `window` object. While `window` + * is globally available in JavaScript, it causes testability problems, because + * it is a global variable. In angular we always refer to it through the + * `$window` service, so it may be overridden, removed or mocked for testing. + * + * Expressions, like the one defined for the `ngClick` directive in the example + * below, are evaluated with respect to the current scope. Therefore, there is + * no risk of inadvertently coding in a dependency on a global value in such an + * expression. + * + * @example + + + +
+ + +
+
+ + it('should display the greeting in the input box', function() { + input('greeting').enter('Hello, E2E Tests'); + // If we click the button it will block the test runner + // element(':button').click(); + }); + +
+ */ +function $WindowProvider(){ + this.$get = valueFn(window); +} + +/** + * @ngdoc object + * @name ng.$filterProvider + * @description + * + * Filters are just functions which transform input to an output. However filters need to be + * Dependency Injected. To achieve this a filter definition consists of a factory function which is + * annotated with dependencies and is responsible for creating a filter function. + * + *
+ *   // Filter registration
+ *   function MyModule($provide, $filterProvider) {
+ *     // create a service to demonstrate injection (not always needed)
+ *     $provide.value('greet', function(name){
+ *       return 'Hello ' + name + '!';
+ *     });
+ *
+ *     // register a filter factory which uses the
+ *     // greet service to demonstrate DI.
+ *     $filterProvider.register('greet', function(greet){
+ *       // return the filter function which uses the greet service
+ *       // to generate salutation
+ *       return function(text) {
+ *         // filters need to be forgiving so check input validity
+ *         return text && greet(text) || text;
+ *       };
+ *     });
+ *   }
+ * 
+ * + * The filter function is registered with the `$injector` under the filter name suffix with + * `Filter`. + * + *
+ *   it('should be the same instance', inject(
+ *     function($filterProvider) {
+ *       $filterProvider.register('reverse', function(){
+ *         return ...;
+ *       });
+ *     },
+ *     function($filter, reverseFilter) {
+ *       expect($filter('reverse')).toBe(reverseFilter);
+ *     });
+ * 
+ * + * + * For more information about how angular filters work, and how to create your own filters, see + * {@link guide/filter Filters} in the Angular Developer Guide. + */ +/** + * @ngdoc method + * @name ng.$filterProvider#register + * @methodOf ng.$filterProvider + * @description + * Register filter factory function. + * + * @param {String} name Name of the filter. + * @param {function} fn The filter factory function which is injectable. + */ + + +/** + * @ngdoc function + * @name ng.$filter + * @function + * @description + * Filters are used for formatting data displayed to the user. + * + * The general syntax in templates is as follows: + * + * {{ expression [| filter_name[:parameter_value] ... ] }} + * + * @param {String} name Name of the filter function to retrieve + * @return {Function} the filter function + */ +$FilterProvider.$inject = ['$provide']; +function $FilterProvider($provide) { + var suffix = 'Filter'; + + /** + * @ngdoc function + * @name ng.$controllerProvider#register + * @methodOf ng.$controllerProvider + * @param {string|Object} name Name of the filter function, or an object map of filters where + * the keys are the filter names and the values are the filter factories. + * @returns {Object} Registered filter instance, or if a map of filters was provided then a map + * of the registered filter instances. + */ + function register(name, factory) { + if(isObject(name)) { + var filters = {}; + forEach(name, function(filter, key) { + filters[key] = register(key, filter); + }); + return filters; + } else { + return $provide.factory(name + suffix, factory); + } + } + this.register = register; + + this.$get = ['$injector', function($injector) { + return function(name) { + return $injector.get(name + suffix); + }; + }]; + + //////////////////////////////////////// + + /* global + currencyFilter: false, + dateFilter: false, + filterFilter: false, + jsonFilter: false, + limitToFilter: false, + lowercaseFilter: false, + numberFilter: false, + orderByFilter: false, + uppercaseFilter: false, + */ + + register('currency', currencyFilter); + register('date', dateFilter); + register('filter', filterFilter); + register('json', jsonFilter); + register('limitTo', limitToFilter); + register('lowercase', lowercaseFilter); + register('number', numberFilter); + register('orderBy', orderByFilter); + register('uppercase', uppercaseFilter); +} + +/** + * @ngdoc filter + * @name ng.filter:filter + * @function + * + * @description + * Selects a subset of items from `array` and returns it as a new array. + * + * @param {Array} array The source array. + * @param {string|Object|function()} expression The predicate to be used for selecting items from + * `array`. + * + * Can be one of: + * + * - `string`: Predicate that results in a substring match using the value of `expression` + * string. All strings or objects with string properties in `array` that contain this string + * will be returned. The predicate can be negated by prefixing the string with `!`. + * + * - `Object`: A pattern object can be used to filter specific properties on objects contained + * by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items + * which have property `name` containing "M" and property `phone` containing "1". A special + * property name `$` can be used (as in `{$:"text"}`) to accept a match against any + * property of the object. That's equivalent to the simple substring match with a `string` + * as described above. + * + * - `function`: A predicate function can be used to write arbitrary filters. The function is + * called for each element of `array`. The final result is an array of those elements that + * the predicate returned true for. + * + * @param {function(expected, actual)|true|undefined} comparator Comparator which is used in + * determining if the expected value (from the filter expression) and actual value (from + * the object in the array) should be considered a match. + * + * Can be one of: + * + * - `function(expected, actual)`: + * The function will be given the object value and the predicate value to compare and + * should return true if the item should be included in filtered result. + * + * - `true`: A shorthand for `function(expected, actual) { return angular.equals(expected, actual)}`. + * this is essentially strict comparison of expected and actual. + * + * - `false|undefined`: A short hand for a function which will look for a substring match in case + * insensitive way. + * + * @example + + +
+ + Search: + + + + + + +
NamePhone
{{friend.name}}{{friend.phone}}
+
+ Any:
+ Name only
+ Phone only
+ Equality
+ + + + + + +
NamePhone
{{friend.name}}{{friend.phone}}
+
+ + it('should search across all fields when filtering with a string', function() { + input('searchText').enter('m'); + expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')). + toEqual(['Mary', 'Mike', 'Adam']); + + input('searchText').enter('76'); + expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')). + toEqual(['John', 'Julie']); + }); + + it('should search in specific fields when filtering with a predicate object', function() { + input('search.$').enter('i'); + expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')). + toEqual(['Mary', 'Mike', 'Julie', 'Juliette']); + }); + it('should use a equal comparison when comparator is true', function() { + input('search.name').enter('Julie'); + input('strict').check(); + expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')). + toEqual(['Julie']); + }); + +
+ */ +function filterFilter() { + return function(array, expression, comparator) { + if (!isArray(array)) return array; + + var comparatorType = typeof(comparator), + predicates = []; + + predicates.check = function(value) { + for (var j = 0; j < predicates.length; j++) { + if(!predicates[j](value)) { + return false; + } + } + return true; + }; + + if (comparatorType !== 'function') { + if (comparatorType === 'boolean' && comparator) { + comparator = function(obj, text) { + return angular.equals(obj, text); + }; + } else { + comparator = function(obj, text) { + text = (''+text).toLowerCase(); + return (''+obj).toLowerCase().indexOf(text) > -1; + }; + } + } + + var search = function(obj, text){ + if (typeof text == 'string' && text.charAt(0) === '!') { + return !search(obj, text.substr(1)); + } + switch (typeof obj) { + case "boolean": + case "number": + case "string": + return comparator(obj, text); + case "object": + switch (typeof text) { + case "object": + return comparator(obj, text); + default: + for ( var objKey in obj) { + if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) { + return true; + } + } + break; + } + return false; + case "array": + for ( var i = 0; i < obj.length; i++) { + if (search(obj[i], text)) { + return true; + } + } + return false; + default: + return false; + } + }; + switch (typeof expression) { + case "boolean": + case "number": + case "string": + // Set up expression object and fall through + expression = {$:expression}; + // jshint -W086 + case "object": + // jshint +W086 + for (var key in expression) { + if (key == '$') { + (function() { + if (!expression[key]) return; + var path = key; + predicates.push(function(value) { + return search(value, expression[path]); + }); + })(); + } else { + (function() { + if (typeof(expression[key]) == 'undefined') { return; } + var path = key; + predicates.push(function(value) { + return search(getter(value,path), expression[path]); + }); + })(); + } + } + break; + case 'function': + predicates.push(expression); + break; + default: + return array; + } + var filtered = []; + for ( var j = 0; j < array.length; j++) { + var value = array[j]; + if (predicates.check(value)) { + filtered.push(value); + } + } + return filtered; + }; +} + +/** + * @ngdoc filter + * @name ng.filter:currency + * @function + * + * @description + * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default + * symbol for current locale is used. + * + * @param {number} amount Input to filter. + * @param {string=} symbol Currency symbol or identifier to be displayed. + * @returns {string} Formatted number. + * + * + * @example + + + +
+
+ default currency symbol ($): {{amount | currency}}
+ custom currency identifier (USD$): {{amount | currency:"USD$"}} +
+
+ + it('should init with 1234.56', function() { + expect(binding('amount | currency')).toBe('$1,234.56'); + expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56'); + }); + it('should update', function() { + input('amount').enter('-1234'); + expect(binding('amount | currency')).toBe('($1,234.00)'); + expect(binding('amount | currency:"USD$"')).toBe('(USD$1,234.00)'); + }); + +
+ */ +currencyFilter.$inject = ['$locale']; +function currencyFilter($locale) { + var formats = $locale.NUMBER_FORMATS; + return function(amount, currencySymbol){ + if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM; + return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2). + replace(/\u00A4/g, currencySymbol); + }; +} + +/** + * @ngdoc filter + * @name ng.filter:number + * @function + * + * @description + * Formats a number as text. + * + * If the input is not a number an empty string is returned. + * + * @param {number|string} number Number to format. + * @param {(number|string)=} fractionSize Number of decimal places to round the number to. + * If this is not provided then the fraction size is computed from the current locale's number + * formatting pattern. In the case of the default locale, it will be 3. + * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit. + * + * @example + + + +
+ Enter number:
+ Default formatting: {{val | number}}
+ No fractions: {{val | number:0}}
+ Negative number: {{-val | number:4}} +
+
+ + it('should format numbers', function() { + expect(binding('val | number')).toBe('1,234.568'); + expect(binding('val | number:0')).toBe('1,235'); + expect(binding('-val | number:4')).toBe('-1,234.5679'); + }); + + it('should update', function() { + input('val').enter('3374.333'); + expect(binding('val | number')).toBe('3,374.333'); + expect(binding('val | number:0')).toBe('3,374'); + expect(binding('-val | number:4')).toBe('-3,374.3330'); + }); + +
+ */ + + +numberFilter.$inject = ['$locale']; +function numberFilter($locale) { + var formats = $locale.NUMBER_FORMATS; + return function(number, fractionSize) { + return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP, + fractionSize); + }; +} + +var DECIMAL_SEP = '.'; +function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { + if (isNaN(number) || !isFinite(number)) return ''; + + var isNegative = number < 0; + number = Math.abs(number); + var numStr = number + '', + formatedText = '', + parts = []; + + var hasExponent = false; + if (numStr.indexOf('e') !== -1) { + var match = numStr.match(/([\d\.]+)e(-?)(\d+)/); + if (match && match[2] == '-' && match[3] > fractionSize + 1) { + numStr = '0'; + } else { + formatedText = numStr; + hasExponent = true; + } + } + + if (!hasExponent) { + var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length; + + // determine fractionSize if it is not specified + if (isUndefined(fractionSize)) { + fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac); + } + + var pow = Math.pow(10, fractionSize); + number = Math.round(number * pow) / pow; + var fraction = ('' + number).split(DECIMAL_SEP); + var whole = fraction[0]; + fraction = fraction[1] || ''; + + var i, pos = 0, + lgroup = pattern.lgSize, + group = pattern.gSize; + + if (whole.length >= (lgroup + group)) { + pos = whole.length - lgroup; + for (i = 0; i < pos; i++) { + if ((pos - i)%group === 0 && i !== 0) { + formatedText += groupSep; + } + formatedText += whole.charAt(i); + } + } + + for (i = pos; i < whole.length; i++) { + if ((whole.length - i)%lgroup === 0 && i !== 0) { + formatedText += groupSep; + } + formatedText += whole.charAt(i); + } + + // format fraction part. + while(fraction.length < fractionSize) { + fraction += '0'; + } + + if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize); + } else { + + if (fractionSize > 0 && number > -1 && number < 1) { + formatedText = number.toFixed(fractionSize); + } + } + + parts.push(isNegative ? pattern.negPre : pattern.posPre); + parts.push(formatedText); + parts.push(isNegative ? pattern.negSuf : pattern.posSuf); + return parts.join(''); +} + +function padNumber(num, digits, trim) { + var neg = ''; + if (num < 0) { + neg = '-'; + num = -num; + } + num = '' + num; + while(num.length < digits) num = '0' + num; + if (trim) + num = num.substr(num.length - digits); + return neg + num; +} + + +function dateGetter(name, size, offset, trim) { + offset = offset || 0; + return function(date) { + var value = date['get' + name](); + if (offset > 0 || value > -offset) + value += offset; + if (value === 0 && offset == -12 ) value = 12; + return padNumber(value, size, trim); + }; +} + +function dateStrGetter(name, shortForm) { + return function(date, formats) { + var value = date['get' + name](); + var get = uppercase(shortForm ? ('SHORT' + name) : name); + + return formats[get][value]; + }; +} + +function timeZoneGetter(date) { + var zone = -1 * date.getTimezoneOffset(); + var paddedZone = (zone >= 0) ? "+" : ""; + + paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) + + padNumber(Math.abs(zone % 60), 2); + + return paddedZone; +} + +function ampmGetter(date, formats) { + return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1]; +} + +var DATE_FORMATS = { + yyyy: dateGetter('FullYear', 4), + yy: dateGetter('FullYear', 2, 0, true), + y: dateGetter('FullYear', 1), + MMMM: dateStrGetter('Month'), + MMM: dateStrGetter('Month', true), + MM: dateGetter('Month', 2, 1), + M: dateGetter('Month', 1, 1), + dd: dateGetter('Date', 2), + d: dateGetter('Date', 1), + HH: dateGetter('Hours', 2), + H: dateGetter('Hours', 1), + hh: dateGetter('Hours', 2, -12), + h: dateGetter('Hours', 1, -12), + mm: dateGetter('Minutes', 2), + m: dateGetter('Minutes', 1), + ss: dateGetter('Seconds', 2), + s: dateGetter('Seconds', 1), + // while ISO 8601 requires fractions to be prefixed with `.` or `,` + // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions + sss: dateGetter('Milliseconds', 3), + EEEE: dateStrGetter('Day'), + EEE: dateStrGetter('Day', true), + a: ampmGetter, + Z: timeZoneGetter +}; + +var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/, + NUMBER_STRING = /^\-?\d+$/; + +/** + * @ngdoc filter + * @name ng.filter:date + * @function + * + * @description + * Formats `date` to a string based on the requested `format`. + * + * `format` string can be composed of the following elements: + * + * * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010) + * * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10) + * * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199) + * * `'MMMM'`: Month in year (January-December) + * * `'MMM'`: Month in year (Jan-Dec) + * * `'MM'`: Month in year, padded (01-12) + * * `'M'`: Month in year (1-12) + * * `'dd'`: Day in month, padded (01-31) + * * `'d'`: Day in month (1-31) + * * `'EEEE'`: Day in Week,(Sunday-Saturday) + * * `'EEE'`: Day in Week, (Sun-Sat) + * * `'HH'`: Hour in day, padded (00-23) + * * `'H'`: Hour in day (0-23) + * * `'hh'`: Hour in am/pm, padded (01-12) + * * `'h'`: Hour in am/pm, (1-12) + * * `'mm'`: Minute in hour, padded (00-59) + * * `'m'`: Minute in hour (0-59) + * * `'ss'`: Second in minute, padded (00-59) + * * `'s'`: Second in minute (0-59) + * * `'.sss' or ',sss'`: Millisecond in second, padded (000-999) + * * `'a'`: am/pm marker + * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200) + * + * `format` string can also be one of the following predefined + * {@link guide/i18n localizable formats}: + * + * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale + * (e.g. Sep 3, 2010 12:05:08 pm) + * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 pm) + * * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US locale + * (e.g. Friday, September 3, 2010) + * * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010) + * * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010) + * * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10) + * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm) + * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm) + * + * `format` string can contain literal values. These need to be quoted with single quotes (e.g. + * `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence + * (e.g. `"h 'o''clock'"`). + * + * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or + * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its + * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is + * specified in the string input, the time is considered to be in the local timezone. + * @param {string=} format Formatting rules (see Description). If not specified, + * `mediumDate` is used. + * @returns {string} Formatted string or the input if input is not recognized as date/millis. + * + * @example + + + {{1288323623006 | date:'medium'}}: + {{1288323623006 | date:'medium'}}
+ {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}: + {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}
+ {{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}: + {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}
+
+ + it('should format date', function() { + expect(binding("1288323623006 | date:'medium'")). + toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/); + expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")). + toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/); + expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")). + toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/); + }); + +
+ */ +dateFilter.$inject = ['$locale']; +function dateFilter($locale) { + + + var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; + // 1 2 3 4 5 6 7 8 9 10 11 + function jsonStringToDate(string) { + var match; + if (match = string.match(R_ISO8601_STR)) { + var date = new Date(0), + tzHour = 0, + tzMin = 0, + dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear, + timeSetter = match[8] ? date.setUTCHours : date.setHours; + + if (match[9]) { + tzHour = int(match[9] + match[10]); + tzMin = int(match[9] + match[11]); + } + dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3])); + var h = int(match[4]||0) - tzHour; + var m = int(match[5]||0) - tzMin; + var s = int(match[6]||0); + var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000); + timeSetter.call(date, h, m, s, ms); + return date; + } + return string; + } + + + return function(date, format) { + var text = '', + parts = [], + fn, match; + + format = format || 'mediumDate'; + format = $locale.DATETIME_FORMATS[format] || format; + if (isString(date)) { + if (NUMBER_STRING.test(date)) { + date = int(date); + } else { + date = jsonStringToDate(date); + } + } + + if (isNumber(date)) { + date = new Date(date); + } + + if (!isDate(date)) { + return date; + } + + while(format) { + match = DATE_FORMATS_SPLIT.exec(format); + if (match) { + parts = concat(parts, match, 1); + format = parts.pop(); + } else { + parts.push(format); + format = null; + } + } + + forEach(parts, function(value){ + fn = DATE_FORMATS[value]; + text += fn ? fn(date, $locale.DATETIME_FORMATS) + : value.replace(/(^'|'$)/g, '').replace(/''/g, "'"); + }); + + return text; + }; +} + + +/** + * @ngdoc filter + * @name ng.filter:json + * @function + * + * @description + * Allows you to convert a JavaScript object into JSON string. + * + * This filter is mostly useful for debugging. When using the double curly {{value}} notation + * the binding is automatically converted to JSON. + * + * @param {*} object Any JavaScript object (including arrays and primitive types) to filter. + * @returns {string} JSON string. + * + * + * @example: + + +
{{ {'name':'value'} | json }}
+
+ + it('should jsonify filtered objects', function() { + expect(binding("{'name':'value'}")).toMatch(/\{\n "name": ?"value"\n}/); + }); + +
+ * + */ +function jsonFilter() { + return function(object) { + return toJson(object, true); + }; +} + + +/** + * @ngdoc filter + * @name ng.filter:lowercase + * @function + * @description + * Converts string to lowercase. + * @see angular.lowercase + */ +var lowercaseFilter = valueFn(lowercase); + + +/** + * @ngdoc filter + * @name ng.filter:uppercase + * @function + * @description + * Converts string to uppercase. + * @see angular.uppercase + */ +var uppercaseFilter = valueFn(uppercase); + +/** + * @ngdoc function + * @name ng.filter:limitTo + * @function + * + * @description + * Creates a new array or string containing only a specified number of elements. The elements + * are taken from either the beginning or the end of the source array or string, as specified by + * the value and sign (positive or negative) of `limit`. + * + * @param {Array|string} input Source array or string to be limited. + * @param {string|number} limit The length of the returned array or string. If the `limit` number + * is positive, `limit` number of items from the beginning of the source array/string are copied. + * If the number is negative, `limit` number of items from the end of the source array/string + * are copied. The `limit` will be trimmed if it exceeds `array.length` + * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array + * had less than `limit` elements. + * + * @example + + + +
+ Limit {{numbers}} to: +

Output numbers: {{ numbers | limitTo:numLimit }}

+ Limit {{letters}} to: +

Output letters: {{ letters | limitTo:letterLimit }}

+
+
+ + it('should limit the number array to first three items', function() { + expect(element('.doc-example-live input[ng-model=numLimit]').val()).toBe('3'); + expect(element('.doc-example-live input[ng-model=letterLimit]').val()).toBe('3'); + expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3]'); + expect(binding('letters | limitTo:letterLimit')).toEqual('abc'); + }); + + it('should update the output when -3 is entered', function() { + input('numLimit').enter(-3); + input('letterLimit').enter(-3); + expect(binding('numbers | limitTo:numLimit')).toEqual('[7,8,9]'); + expect(binding('letters | limitTo:letterLimit')).toEqual('ghi'); + }); + + it('should not exceed the maximum size of input array', function() { + input('numLimit').enter(100); + input('letterLimit').enter(100); + expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3,4,5,6,7,8,9]'); + expect(binding('letters | limitTo:letterLimit')).toEqual('abcdefghi'); + }); + +
+ */ +function limitToFilter(){ + return function(input, limit) { + if (!isArray(input) && !isString(input)) return input; + + limit = int(limit); + + if (isString(input)) { + //NaN check on limit + if (limit) { + return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length); + } else { + return ""; + } + } + + var out = [], + i, n; + + // if abs(limit) exceeds maximum length, trim it + if (limit > input.length) + limit = input.length; + else if (limit < -input.length) + limit = -input.length; + + if (limit > 0) { + i = 0; + n = limit; + } else { + i = input.length + limit; + n = input.length; + } + + for (; i} expression A predicate to be + * used by the comparator to determine the order of elements. + * + * Can be one of: + * + * - `function`: Getter function. The result of this function will be sorted using the + * `<`, `=`, `>` operator. + * - `string`: An Angular expression which evaluates to an object to order by, such as 'name' + * to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control + * ascending or descending sort order (for example, +name or -name). + * - `Array`: An array of function or string predicates. The first predicate in the array + * is used for sorting, but when two items are equivalent, the next predicate is used. + * + * @param {boolean=} reverse Reverse the order the array. + * @returns {Array} Sorted copy of the source array. + * + * @example + + + +
+
Sorting predicate = {{predicate}}; reverse = {{reverse}}
+
+ [ unsorted ] + + + + + + + + + + + +
Name + (^)Phone NumberAge
{{friend.name}}{{friend.phone}}{{friend.age}}
+
+
+ + it('should be reverse ordered by aged', function() { + expect(binding('predicate')).toBe('-age'); + expect(repeater('table.friend', 'friend in friends').column('friend.age')). + toEqual(['35', '29', '21', '19', '10']); + expect(repeater('table.friend', 'friend in friends').column('friend.name')). + toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']); + }); + + it('should reorder the table when user selects different predicate', function() { + element('.doc-example-live a:contains("Name")').click(); + expect(repeater('table.friend', 'friend in friends').column('friend.name')). + toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']); + expect(repeater('table.friend', 'friend in friends').column('friend.age')). + toEqual(['35', '10', '29', '19', '21']); + + element('.doc-example-live a:contains("Phone")').click(); + expect(repeater('table.friend', 'friend in friends').column('friend.phone')). + toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']); + expect(repeater('table.friend', 'friend in friends').column('friend.name')). + toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']); + }); + +
+ */ +orderByFilter.$inject = ['$parse']; +function orderByFilter($parse){ + return function(array, sortPredicate, reverseOrder) { + if (!isArray(array)) return array; + if (!sortPredicate) return array; + sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate]; + sortPredicate = map(sortPredicate, function(predicate){ + var descending = false, get = predicate || identity; + if (isString(predicate)) { + if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) { + descending = predicate.charAt(0) == '-'; + predicate = predicate.substring(1); + } + get = $parse(predicate); + } + return reverseComparator(function(a,b){ + return compare(get(a),get(b)); + }, descending); + }); + var arrayCopy = []; + for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); } + return arrayCopy.sort(reverseComparator(comparator, reverseOrder)); + + function comparator(o1, o2){ + for ( var i = 0; i < sortPredicate.length; i++) { + var comp = sortPredicate[i](o1, o2); + if (comp !== 0) return comp; + } + return 0; + } + function reverseComparator(comp, descending) { + return toBoolean(descending) + ? function(a,b){return comp(b,a);} + : comp; + } + function compare(v1, v2){ + var t1 = typeof v1; + var t2 = typeof v2; + if (t1 == t2) { + if (t1 == "string") { + v1 = v1.toLowerCase(); + v2 = v2.toLowerCase(); + } + if (v1 === v2) return 0; + return v1 < v2 ? -1 : 1; + } else { + return t1 < t2 ? -1 : 1; + } + } + }; +} + +function ngDirective(directive) { + if (isFunction(directive)) { + directive = { + link: directive + }; + } + directive.restrict = directive.restrict || 'AC'; + return valueFn(directive); +} + +/** + * @ngdoc directive + * @name ng.directive:a + * @restrict E + * + * @description + * Modifies the default behavior of the html A tag so that the default action is prevented when + * the href attribute is empty. + * + * This change permits the easy creation of action links with the `ngClick` directive + * without changing the location or causing page reloads, e.g.: + * `Add Item` + */ +var htmlAnchorDirective = valueFn({ + restrict: 'E', + compile: function(element, attr) { + + if (msie <= 8) { + + // turn link into a stylable link in IE + // but only if it doesn't have name attribute, in which case it's an anchor + if (!attr.href && !attr.name) { + attr.$set('href', ''); + } + + // add a comment node to anchors to workaround IE bug that causes element content to be reset + // to new attribute content if attribute is updated with value containing @ and element also + // contains value with @ + // see issue #1949 + element.append(document.createComment('IE fix')); + } + + return function(scope, element) { + element.on('click', function(event){ + // if we have no href url, then don't navigate anywhere. + if (!element.attr('href')) { + event.preventDefault(); + } + }); + }; + } +}); + +/** + * @ngdoc directive + * @name ng.directive:ngHref + * @restrict A + * + * @description + * Using Angular markup like `{{hash}}` in an href attribute will + * make the link go to the wrong URL if the user clicks it before + * Angular has a chance to replace the `{{hash}}` markup with its + * value. Until Angular replaces the markup the link will be broken + * and will most likely return a 404 error. + * + * The `ngHref` directive solves this problem. + * + * The wrong way to write it: + *
+ * 
+ * 
+ * + * The correct way to write it: + *
+ * 
+ * 
+ * + * @element A + * @param {template} ngHref any string which can contain `{{}}` markup. + * + * @example + * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes + * in links and their different behaviors: + + +
+
link 1 (link, don't reload)
+ link 2 (link, don't reload)
+ link 3 (link, reload!)
+ anchor (link, don't reload)
+ anchor (no link)
+ link (link, change location) + + + it('should execute ng-click but not reload when href without value', function() { + element('#link-1').click(); + expect(input('value').val()).toEqual('1'); + expect(element('#link-1').attr('href')).toBe(""); + }); + + it('should execute ng-click but not reload when href empty string', function() { + element('#link-2').click(); + expect(input('value').val()).toEqual('2'); + expect(element('#link-2').attr('href')).toBe(""); + }); + + it('should execute ng-click and change url when ng-href specified', function() { + expect(element('#link-3').attr('href')).toBe("/123"); + + element('#link-3').click(); + expect(browser().window().path()).toEqual('/123'); + }); + + it('should execute ng-click but not reload when href empty string and name specified', function() { + element('#link-4').click(); + expect(input('value').val()).toEqual('4'); + expect(element('#link-4').attr('href')).toBe(''); + }); + + it('should execute ng-click but not reload when no href but name specified', function() { + element('#link-5').click(); + expect(input('value').val()).toEqual('5'); + expect(element('#link-5').attr('href')).toBe(undefined); + }); + + it('should only change url when only ng-href', function() { + input('value').enter('6'); + expect(element('#link-6').attr('href')).toBe('6'); + + element('#link-6').click(); + expect(browser().location().url()).toEqual('/6'); + }); + + + */ + +/** + * @ngdoc directive + * @name ng.directive:ngSrc + * @restrict A + * + * @description + * Using Angular markup like `{{hash}}` in a `src` attribute doesn't + * work right: The browser will fetch from the URL with the literal + * text `{{hash}}` until Angular replaces the expression inside + * `{{hash}}`. The `ngSrc` directive solves this problem. + * + * The buggy way to write it: + *
+ * 
+ * 
+ * + * The correct way to write it: + *
+ * 
+ * 
+ * + * @element IMG + * @param {template} ngSrc any string which can contain `{{}}` markup. + */ + +/** + * @ngdoc directive + * @name ng.directive:ngSrcset + * @restrict A + * + * @description + * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't + * work right: The browser will fetch from the URL with the literal + * text `{{hash}}` until Angular replaces the expression inside + * `{{hash}}`. The `ngSrcset` directive solves this problem. + * + * The buggy way to write it: + *
+ * 
+ * 
+ * + * The correct way to write it: + *
+ * 
+ * 
+ * + * @element IMG + * @param {template} ngSrcset any string which can contain `{{}}` markup. + */ + +/** + * @ngdoc directive + * @name ng.directive:ngDisabled + * @restrict A + * + * @description + * + * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs: + *
+ * 
+ * + *
+ *
+ * + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as disabled. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngDisabled` directive solves this problem for the `disabled` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * + * @example + + + Click me to toggle:
+ +
+ + it('should toggle button', function() { + expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy(); + input('checked').check(); + expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy(); + }); + +
+ * + * @element INPUT + * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy, + * then special attribute "disabled" will be set on the element + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngChecked + * @restrict A + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as checked. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngChecked` directive solves this problem for the `checked` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * @example + + + Check me to check both:
+ +
+ + it('should check both checkBoxes', function() { + expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy(); + input('master').check(); + expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy(); + }); + +
+ * + * @element INPUT + * @param {expression} ngChecked If the {@link guide/expression expression} is truthy, + * then special attribute "checked" will be set on the element + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngReadonly + * @restrict A + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as readonly. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngReadonly` directive solves this problem for the `readonly` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + + * @example + + + Check me to make text readonly:
+ +
+ + it('should toggle readonly attr', function() { + expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy(); + input('checked').check(); + expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy(); + }); + +
+ * + * @element INPUT + * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy, + * then special attribute "readonly" will be set on the element + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngSelected + * @restrict A + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as selected. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngSelected` directive solves this problem for the `selected` atttribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * @example + + + Check me to select:
+ +
+ + it('should select Greetings!', function() { + expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy(); + input('selected').check(); + expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy(); + }); + +
+ * + * @element OPTION + * @param {expression} ngSelected If the {@link guide/expression expression} is truthy, + * then special attribute "selected" will be set on the element + */ + +/** + * @ngdoc directive + * @name ng.directive:ngOpen + * @restrict A + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as open. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngOpen` directive solves this problem for the `open` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + + * + * @example + + + Check me check multiple:
+
+ Show/Hide me +
+
+ + it('should toggle open', function() { + expect(element('#details').prop('open')).toBeFalsy(); + input('open').check(); + expect(element('#details').prop('open')).toBeTruthy(); + }); + +
+ * + * @element DETAILS + * @param {expression} ngOpen If the {@link guide/expression expression} is truthy, + * then special attribute "open" will be set on the element + */ + +var ngAttributeAliasDirectives = {}; + + +// boolean attrs are evaluated +forEach(BOOLEAN_ATTR, function(propName, attrName) { + // binding to multiple is not supported + if (propName == "multiple") return; + + var normalized = directiveNormalize('ng-' + attrName); + ngAttributeAliasDirectives[normalized] = function() { + return { + priority: 100, + compile: function() { + return function(scope, element, attr) { + scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) { + attr.$set(attrName, !!value); + }); + }; + } + }; + }; +}); + + +// ng-src, ng-srcset, ng-href are interpolated +forEach(['src', 'srcset', 'href'], function(attrName) { + var normalized = directiveNormalize('ng-' + attrName); + ngAttributeAliasDirectives[normalized] = function() { + return { + priority: 99, // it needs to run after the attributes are interpolated + link: function(scope, element, attr) { + attr.$observe(normalized, function(value) { + if (!value) + return; + + attr.$set(attrName, value); + + // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist + // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need + // to set the property as well to achieve the desired effect. + // we use attr[attrName] value since $set can sanitize the url. + if (msie) element.prop(attrName, attr[attrName]); + }); + } + }; + }; +}); + +/* global -nullFormCtrl */ +var nullFormCtrl = { + $addControl: noop, + $removeControl: noop, + $setValidity: noop, + $setDirty: noop, + $setPristine: noop +}; + +/** + * @ngdoc object + * @name ng.directive:form.FormController + * + * @property {boolean} $pristine True if user has not interacted with the form yet. + * @property {boolean} $dirty True if user has already interacted with the form. + * @property {boolean} $valid True if all of the containing forms and controls are valid. + * @property {boolean} $invalid True if at least one containing control or form is invalid. + * + * @property {Object} $error Is an object hash, containing references to all invalid controls or + * forms, where: + * + * - keys are validation tokens (error names) — such as `required`, `url` or `email`, + * - values are arrays of controls or forms that are invalid with given error. + * + * @description + * `FormController` keeps track of all its controls and nested forms as well as state of them, + * such as being valid/invalid or dirty/pristine. + * + * Each {@link ng.directive:form form} directive creates an instance + * of `FormController`. + * + */ +//asks for $scope to fool the BC controller module +FormController.$inject = ['$element', '$attrs', '$scope']; +function FormController(element, attrs) { + var form = this, + parentForm = element.parent().controller('form') || nullFormCtrl, + invalidCount = 0, // used to easily determine if we are valid + errors = form.$error = {}, + controls = []; + + // init state + form.$name = attrs.name || attrs.ngForm; + form.$dirty = false; + form.$pristine = true; + form.$valid = true; + form.$invalid = false; + + parentForm.$addControl(form); + + // Setup initial state of the control + element.addClass(PRISTINE_CLASS); + toggleValidCss(true); + + // convenience method for easy toggling of classes + function toggleValidCss(isValid, validationErrorKey) { + validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : ''; + element. + removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey). + addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey); + } + + /** + * @ngdoc function + * @name ng.directive:form.FormController#$addControl + * @methodOf ng.directive:form.FormController + * + * @description + * Register a control with the form. + * + * Input elements using ngModelController do this automatically when they are linked. + */ + form.$addControl = function(control) { + // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored + // and not added to the scope. Now we throw an error. + assertNotHasOwnProperty(control.$name, 'input'); + controls.push(control); + + if (control.$name) { + form[control.$name] = control; + } + }; + + /** + * @ngdoc function + * @name ng.directive:form.FormController#$removeControl + * @methodOf ng.directive:form.FormController + * + * @description + * Deregister a control from the form. + * + * Input elements using ngModelController do this automatically when they are destroyed. + */ + form.$removeControl = function(control) { + if (control.$name && form[control.$name] === control) { + delete form[control.$name]; + } + forEach(errors, function(queue, validationToken) { + form.$setValidity(validationToken, true, control); + }); + + arrayRemove(controls, control); + }; + + /** + * @ngdoc function + * @name ng.directive:form.FormController#$setValidity + * @methodOf ng.directive:form.FormController + * + * @description + * Sets the validity of a form control. + * + * This method will also propagate to parent forms. + */ + form.$setValidity = function(validationToken, isValid, control) { + var queue = errors[validationToken]; + + if (isValid) { + if (queue) { + arrayRemove(queue, control); + if (!queue.length) { + invalidCount--; + if (!invalidCount) { + toggleValidCss(isValid); + form.$valid = true; + form.$invalid = false; + } + errors[validationToken] = false; + toggleValidCss(true, validationToken); + parentForm.$setValidity(validationToken, true, form); + } + } + + } else { + if (!invalidCount) { + toggleValidCss(isValid); + } + if (queue) { + if (includes(queue, control)) return; + } else { + errors[validationToken] = queue = []; + invalidCount++; + toggleValidCss(false, validationToken); + parentForm.$setValidity(validationToken, false, form); + } + queue.push(control); + + form.$valid = false; + form.$invalid = true; + } + }; + + /** + * @ngdoc function + * @name ng.directive:form.FormController#$setDirty + * @methodOf ng.directive:form.FormController + * + * @description + * Sets the form to a dirty state. + * + * This method can be called to add the 'ng-dirty' class and set the form to a dirty + * state (ng-dirty class). This method will also propagate to parent forms. + */ + form.$setDirty = function() { + element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS); + form.$dirty = true; + form.$pristine = false; + parentForm.$setDirty(); + }; + + /** + * @ngdoc function + * @name ng.directive:form.FormController#$setPristine + * @methodOf ng.directive:form.FormController + * + * @description + * Sets the form to its pristine state. + * + * This method can be called to remove the 'ng-dirty' class and set the form to its pristine + * state (ng-pristine class). This method will also propagate to all the controls contained + * in this form. + * + * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after + * saving or resetting it. + */ + form.$setPristine = function () { + element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS); + form.$dirty = false; + form.$pristine = true; + forEach(controls, function(control) { + control.$setPristine(); + }); + }; +} + + +/** + * @ngdoc directive + * @name ng.directive:ngForm + * @restrict EAC + * + * @description + * Nestable alias of {@link ng.directive:form `form`} directive. HTML + * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a + * sub-group of controls needs to be determined. + * + * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into + * related scope, under this name. + * + */ + + /** + * @ngdoc directive + * @name ng.directive:form + * @restrict E + * + * @description + * Directive that instantiates + * {@link ng.directive:form.FormController FormController}. + * + * If the `name` attribute is specified, the form controller is published onto the current scope under + * this name. + * + * # Alias: {@link ng.directive:ngForm `ngForm`} + * + * In Angular forms can be nested. This means that the outer form is valid when all of the child + * forms are valid as well. However, browsers do not allow nesting of `
` elements, so + * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to + * `` but can be nested. This allows you to have nested forms, which is very useful when + * using Angular validation directives in forms that are dynamically generated using the + * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name` + * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an + * `ngForm` directive and nest these in an outer `form` element. + * + * + * # CSS classes + * - `ng-valid` Is set if the form is valid. + * - `ng-invalid` Is set if the form is invalid. + * - `ng-pristine` Is set if the form is pristine. + * - `ng-dirty` Is set if the form is dirty. + * + * + * # Submitting a form and preventing the default action + * + * Since the role of forms in client-side Angular applications is different than in classical + * roundtrip apps, it is desirable for the browser not to translate the form submission into a full + * page reload that sends the data to the server. Instead some javascript logic should be triggered + * to handle the form submission in an application-specific way. + * + * For this reason, Angular prevents the default action (form submission to the server) unless the + * `` element has an `action` attribute specified. + * + * You can use one of the following two ways to specify what javascript method should be called when + * a form is submitted: + * + * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element + * - {@link ng.directive:ngClick ngClick} directive on the first + * button or input field of type submit (input[type=submit]) + * + * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit} + * or {@link ng.directive:ngClick ngClick} directives. + * This is because of the following form submission rules in the HTML specification: + * + * - If a form has only one input field then hitting enter in this field triggers form submit + * (`ngSubmit`) + * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter + * doesn't trigger submit + * - if a form has one or more input fields and one or more buttons or input[type=submit] then + * hitting enter in any of the input fields will trigger the click handler on the *first* button or + * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`) + * + * @param {string=} name Name of the form. If specified, the form controller will be published into + * related scope, under this name. + * + * @example + + + + + userType: + Required!
+ userType = {{userType}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+ +
+ + it('should initialize to model', function() { + expect(binding('userType')).toEqual('guest'); + expect(binding('myForm.input.$valid')).toEqual('true'); + }); + + it('should be invalid if empty', function() { + input('userType').enter(''); + expect(binding('userType')).toEqual(''); + expect(binding('myForm.input.$valid')).toEqual('false'); + }); + +
+ */ +var formDirectiveFactory = function(isNgForm) { + return ['$timeout', function($timeout) { + var formDirective = { + name: 'form', + restrict: isNgForm ? 'EAC' : 'E', + controller: FormController, + compile: function() { + return { + pre: function(scope, formElement, attr, controller) { + if (!attr.action) { + // we can't use jq events because if a form is destroyed during submission the default + // action is not prevented. see #1238 + // + // IE 9 is not affected because it doesn't fire a submit event and try to do a full + // page reload if the form was destroyed by submission of the form via a click handler + // on a button in the form. Looks like an IE9 specific bug. + var preventDefaultListener = function(event) { + event.preventDefault + ? event.preventDefault() + : event.returnValue = false; // IE + }; + + addEventListenerFn(formElement[0], 'submit', preventDefaultListener); + + // unregister the preventDefault listener so that we don't not leak memory but in a + // way that will achieve the prevention of the default action. + formElement.on('$destroy', function() { + $timeout(function() { + removeEventListenerFn(formElement[0], 'submit', preventDefaultListener); + }, 0, false); + }); + } + + var parentFormCtrl = formElement.parent().controller('form'), + alias = attr.name || attr.ngForm; + + if (alias) { + setter(scope, alias, controller, alias); + } + if (parentFormCtrl) { + formElement.on('$destroy', function() { + parentFormCtrl.$removeControl(controller); + if (alias) { + setter(scope, alias, undefined, alias); + } + extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards + }); + } + } + }; + } + }; + + return formDirective; + }]; +}; + +var formDirective = formDirectiveFactory(); +var ngFormDirective = formDirectiveFactory(true); + +/* global + + -VALID_CLASS, + -INVALID_CLASS, + -PRISTINE_CLASS, + -DIRTY_CLASS +*/ + +var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/; +var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/; +var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/; + +var inputType = { + + /** + * @ngdoc inputType + * @name ng.directive:input.text + * + * @description + * Standard HTML text input with angular data binding. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Adds `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. + * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the + * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + * patterns defined as scope expressions. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. + * + * @example + + + +
+ Single word: + + Required! + + Single word only! + + text = {{text}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+
+
+ + it('should initialize to model', function() { + expect(binding('text')).toEqual('guest'); + expect(binding('myForm.input.$valid')).toEqual('true'); + }); + + it('should be invalid if empty', function() { + input('text').enter(''); + expect(binding('text')).toEqual(''); + expect(binding('myForm.input.$valid')).toEqual('false'); + }); + + it('should be invalid if multi word', function() { + input('text').enter('hello world'); + expect(binding('myForm.input.$valid')).toEqual('false'); + }); + + it('should not be trimmed', function() { + input('text').enter('untrimmed '); + expect(binding('text')).toEqual('untrimmed '); + expect(binding('myForm.input.$valid')).toEqual('true'); + }); + +
+ */ + 'text': textInputType, + + + /** + * @ngdoc inputType + * @name ng.directive:input.number + * + * @description + * Text input with number validation and transformation. Sets the `number` validation + * error if not a valid number. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. + * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the + * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + * patterns defined as scope expressions. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
+ Number: + + Required! + + Not valid number! + value = {{value}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+
+
+ + it('should initialize to model', function() { + expect(binding('value')).toEqual('12'); + expect(binding('myForm.input.$valid')).toEqual('true'); + }); + + it('should be invalid if empty', function() { + input('value').enter(''); + expect(binding('value')).toEqual(''); + expect(binding('myForm.input.$valid')).toEqual('false'); + }); + + it('should be invalid if over max', function() { + input('value').enter('123'); + expect(binding('value')).toEqual(''); + expect(binding('myForm.input.$valid')).toEqual('false'); + }); + +
+ */ + 'number': numberInputType, + + + /** + * @ngdoc inputType + * @name ng.directive:input.url + * + * @description + * Text input with URL validation. Sets the `url` validation error key if the content is not a + * valid URL. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. + * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the + * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + * patterns defined as scope expressions. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
+ URL: + + Required! + + Not valid url! + text = {{text}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+ myForm.$error.url = {{!!myForm.$error.url}}
+
+
+ + it('should initialize to model', function() { + expect(binding('text')).toEqual('http://google.com'); + expect(binding('myForm.input.$valid')).toEqual('true'); + }); + + it('should be invalid if empty', function() { + input('text').enter(''); + expect(binding('text')).toEqual(''); + expect(binding('myForm.input.$valid')).toEqual('false'); + }); + + it('should be invalid if not url', function() { + input('text').enter('xxx'); + expect(binding('myForm.input.$valid')).toEqual('false'); + }); + +
+ */ + 'url': urlInputType, + + + /** + * @ngdoc inputType + * @name ng.directive:input.email + * + * @description + * Text input with email validation. Sets the `email` validation error key if not a valid email + * address. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. + * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the + * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + * patterns defined as scope expressions. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
+ Email: + + Required! + + Not valid email! + text = {{text}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+ myForm.$error.email = {{!!myForm.$error.email}}
+
+
+ + it('should initialize to model', function() { + expect(binding('text')).toEqual('me@example.com'); + expect(binding('myForm.input.$valid')).toEqual('true'); + }); + + it('should be invalid if empty', function() { + input('text').enter(''); + expect(binding('text')).toEqual(''); + expect(binding('myForm.input.$valid')).toEqual('false'); + }); + + it('should be invalid if not email', function() { + input('text').enter('xxx'); + expect(binding('myForm.input.$valid')).toEqual('false'); + }); + +
+ */ + 'email': emailInputType, + + + /** + * @ngdoc inputType + * @name ng.directive:input.radio + * + * @description + * HTML radio button. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} value The value to which the expression should be set when selected. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
+ Red
+ Green
+ Blue
+ color = {{color}}
+
+
+ + it('should change state', function() { + expect(binding('color')).toEqual('blue'); + + input('color').select('red'); + expect(binding('color')).toEqual('red'); + }); + +
+ */ + 'radio': radioInputType, + + + /** + * @ngdoc inputType + * @name ng.directive:input.checkbox + * + * @description + * HTML checkbox. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} ngTrueValue The value to which the expression should be set when selected. + * @param {string=} ngFalseValue The value to which the expression should be set when not selected. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
+ Value1:
+ Value2:
+ value1 = {{value1}}
+ value2 = {{value2}}
+
+
+ + it('should change state', function() { + expect(binding('value1')).toEqual('true'); + expect(binding('value2')).toEqual('YES'); + + input('value1').check(); + input('value2').check(); + expect(binding('value1')).toEqual('false'); + expect(binding('value2')).toEqual('NO'); + }); + +
+ */ + 'checkbox': checkboxInputType, + + 'hidden': noop, + 'button': noop, + 'submit': noop, + 'reset': noop +}; + + +function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { + // In composition mode, users are still inputing intermediate text buffer, + // hold the listener until composition is done. + // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent + var composing = false; + + element.on('compositionstart', function() { + composing = true; + }); + + element.on('compositionend', function() { + composing = false; + }); + + var listener = function() { + if (composing) return; + var value = element.val(); + + // By default we will trim the value + // If the attribute ng-trim exists we will avoid trimming + // e.g. + if (toBoolean(attr.ngTrim || 'T')) { + value = trim(value); + } + + if (ctrl.$viewValue !== value) { + scope.$apply(function() { + ctrl.$setViewValue(value); + }); + } + }; + + // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the + // input event on backspace, delete or cut + if ($sniffer.hasEvent('input')) { + element.on('input', listener); + } else { + var timeout; + + var deferListener = function() { + if (!timeout) { + timeout = $browser.defer(function() { + listener(); + timeout = null; + }); + } + }; + + element.on('keydown', function(event) { + var key = event.keyCode; + + // ignore + // command modifiers arrows + if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return; + + deferListener(); + }); + + // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it + if ($sniffer.hasEvent('paste')) { + element.on('paste cut', deferListener); + } + } + + // if user paste into input using mouse on older browser + // or form autocomplete on newer browser, we need "change" event to catch it + element.on('change', listener); + + ctrl.$render = function() { + element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue); + }; + + // pattern validator + var pattern = attr.ngPattern, + patternValidator, + match; + + var validate = function(regexp, value) { + if (ctrl.$isEmpty(value) || regexp.test(value)) { + ctrl.$setValidity('pattern', true); + return value; + } else { + ctrl.$setValidity('pattern', false); + return undefined; + } + }; + + if (pattern) { + match = pattern.match(/^\/(.*)\/([gim]*)$/); + if (match) { + pattern = new RegExp(match[1], match[2]); + patternValidator = function(value) { + return validate(pattern, value); + }; + } else { + patternValidator = function(value) { + var patternObj = scope.$eval(pattern); + + if (!patternObj || !patternObj.test) { + throw minErr('ngPattern')('noregexp', + 'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern, + patternObj, startingTag(element)); + } + return validate(patternObj, value); + }; + } + + ctrl.$formatters.push(patternValidator); + ctrl.$parsers.push(patternValidator); + } + + // min length validator + if (attr.ngMinlength) { + var minlength = int(attr.ngMinlength); + var minLengthValidator = function(value) { + if (!ctrl.$isEmpty(value) && value.length < minlength) { + ctrl.$setValidity('minlength', false); + return undefined; + } else { + ctrl.$setValidity('minlength', true); + return value; + } + }; + + ctrl.$parsers.push(minLengthValidator); + ctrl.$formatters.push(minLengthValidator); + } + + // max length validator + if (attr.ngMaxlength) { + var maxlength = int(attr.ngMaxlength); + var maxLengthValidator = function(value) { + if (!ctrl.$isEmpty(value) && value.length > maxlength) { + ctrl.$setValidity('maxlength', false); + return undefined; + } else { + ctrl.$setValidity('maxlength', true); + return value; + } + }; + + ctrl.$parsers.push(maxLengthValidator); + ctrl.$formatters.push(maxLengthValidator); + } +} + +function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { + textInputType(scope, element, attr, ctrl, $sniffer, $browser); + + ctrl.$parsers.push(function(value) { + var empty = ctrl.$isEmpty(value); + if (empty || NUMBER_REGEXP.test(value)) { + ctrl.$setValidity('number', true); + return value === '' ? null : (empty ? value : parseFloat(value)); + } else { + ctrl.$setValidity('number', false); + return undefined; + } + }); + + ctrl.$formatters.push(function(value) { + return ctrl.$isEmpty(value) ? '' : '' + value; + }); + + if (attr.min) { + var minValidator = function(value) { + var min = parseFloat(attr.min); + if (!ctrl.$isEmpty(value) && value < min) { + ctrl.$setValidity('min', false); + return undefined; + } else { + ctrl.$setValidity('min', true); + return value; + } + }; + + ctrl.$parsers.push(minValidator); + ctrl.$formatters.push(minValidator); + } + + if (attr.max) { + var maxValidator = function(value) { + var max = parseFloat(attr.max); + if (!ctrl.$isEmpty(value) && value > max) { + ctrl.$setValidity('max', false); + return undefined; + } else { + ctrl.$setValidity('max', true); + return value; + } + }; + + ctrl.$parsers.push(maxValidator); + ctrl.$formatters.push(maxValidator); + } + + ctrl.$formatters.push(function(value) { + + if (ctrl.$isEmpty(value) || isNumber(value)) { + ctrl.$setValidity('number', true); + return value; + } else { + ctrl.$setValidity('number', false); + return undefined; + } + }); +} + +function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) { + textInputType(scope, element, attr, ctrl, $sniffer, $browser); + + var urlValidator = function(value) { + if (ctrl.$isEmpty(value) || URL_REGEXP.test(value)) { + ctrl.$setValidity('url', true); + return value; + } else { + ctrl.$setValidity('url', false); + return undefined; + } + }; + + ctrl.$formatters.push(urlValidator); + ctrl.$parsers.push(urlValidator); +} + +function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) { + textInputType(scope, element, attr, ctrl, $sniffer, $browser); + + var emailValidator = function(value) { + if (ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value)) { + ctrl.$setValidity('email', true); + return value; + } else { + ctrl.$setValidity('email', false); + return undefined; + } + }; + + ctrl.$formatters.push(emailValidator); + ctrl.$parsers.push(emailValidator); +} + +function radioInputType(scope, element, attr, ctrl) { + // make the name unique, if not defined + if (isUndefined(attr.name)) { + element.attr('name', nextUid()); + } + + element.on('click', function() { + if (element[0].checked) { + scope.$apply(function() { + ctrl.$setViewValue(attr.value); + }); + } + }); + + ctrl.$render = function() { + var value = attr.value; + element[0].checked = (value == ctrl.$viewValue); + }; + + attr.$observe('value', ctrl.$render); +} + +function checkboxInputType(scope, element, attr, ctrl) { + var trueValue = attr.ngTrueValue, + falseValue = attr.ngFalseValue; + + if (!isString(trueValue)) trueValue = true; + if (!isString(falseValue)) falseValue = false; + + element.on('click', function() { + scope.$apply(function() { + ctrl.$setViewValue(element[0].checked); + }); + }); + + ctrl.$render = function() { + element[0].checked = ctrl.$viewValue; + }; + + // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox. + ctrl.$isEmpty = function(value) { + return value !== trueValue; + }; + + ctrl.$formatters.push(function(value) { + return value === trueValue; + }); + + ctrl.$parsers.push(function(value) { + return value ? trueValue : falseValue; + }); +} + + +/** + * @ngdoc directive + * @name ng.directive:textarea + * @restrict E + * + * @description + * HTML textarea element control with angular data-binding. The data-binding and validation + * properties of this element are exactly the same as those of the + * {@link ng.directive:input input element}. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. + * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the + * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + * patterns defined as scope expressions. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + */ + + +/** + * @ngdoc directive + * @name ng.directive:input + * @restrict E + * + * @description + * HTML input element control with angular data-binding. Input control follows HTML5 input types + * and polyfills the HTML5 validation behavior for older browsers. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {boolean=} ngRequired Sets `required` attribute if set to true + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. + * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the + * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + * patterns defined as scope expressions. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
+
+ User name: + + Required!
+ Last name: + + Too short! + + Too long!
+
+
+ user = {{user}}
+ myForm.userName.$valid = {{myForm.userName.$valid}}
+ myForm.userName.$error = {{myForm.userName.$error}}
+ myForm.lastName.$valid = {{myForm.lastName.$valid}}
+ myForm.lastName.$error = {{myForm.lastName.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+ myForm.$error.minlength = {{!!myForm.$error.minlength}}
+ myForm.$error.maxlength = {{!!myForm.$error.maxlength}}
+
+
+ + it('should initialize to model', function() { + expect(binding('user')).toEqual('{"name":"guest","last":"visitor"}'); + expect(binding('myForm.userName.$valid')).toEqual('true'); + expect(binding('myForm.$valid')).toEqual('true'); + }); + + it('should be invalid if empty when required', function() { + input('user.name').enter(''); + expect(binding('user')).toEqual('{"last":"visitor"}'); + expect(binding('myForm.userName.$valid')).toEqual('false'); + expect(binding('myForm.$valid')).toEqual('false'); + }); + + it('should be valid if empty when min length is set', function() { + input('user.last').enter(''); + expect(binding('user')).toEqual('{"name":"guest","last":""}'); + expect(binding('myForm.lastName.$valid')).toEqual('true'); + expect(binding('myForm.$valid')).toEqual('true'); + }); + + it('should be invalid if less than required min length', function() { + input('user.last').enter('xx'); + expect(binding('user')).toEqual('{"name":"guest"}'); + expect(binding('myForm.lastName.$valid')).toEqual('false'); + expect(binding('myForm.lastName.$error')).toMatch(/minlength/); + expect(binding('myForm.$valid')).toEqual('false'); + }); + + it('should be invalid if longer than max length', function() { + input('user.last').enter('some ridiculously long name'); + expect(binding('user')) + .toEqual('{"name":"guest"}'); + expect(binding('myForm.lastName.$valid')).toEqual('false'); + expect(binding('myForm.lastName.$error')).toMatch(/maxlength/); + expect(binding('myForm.$valid')).toEqual('false'); + }); + +
+ */ +var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) { + return { + restrict: 'E', + require: '?ngModel', + link: function(scope, element, attr, ctrl) { + if (ctrl) { + (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer, + $browser); + } + } + }; +}]; + +var VALID_CLASS = 'ng-valid', + INVALID_CLASS = 'ng-invalid', + PRISTINE_CLASS = 'ng-pristine', + DIRTY_CLASS = 'ng-dirty'; + +/** + * @ngdoc object + * @name ng.directive:ngModel.NgModelController + * + * @property {string} $viewValue Actual string value in the view. + * @property {*} $modelValue The value in the model, that the control is bound to. + * @property {Array.} $parsers Array of functions to execute, as a pipeline, whenever + the control reads value from the DOM. Each function is called, in turn, passing the value + through to the next. Used to sanitize / convert the value as well as validation. + For validation, the parsers should update the validity state using + {@link ng.directive:ngModel.NgModelController#methods_$setValidity $setValidity()}, + and return `undefined` for invalid values. + + * + * @property {Array.} $formatters Array of functions to execute, as a pipeline, whenever + the model value changes. Each function is called, in turn, passing the value through to the + next. Used to format / convert values for display in the control and validation. + *
+ *      function formatter(value) {
+ *        if (value) {
+ *          return value.toUpperCase();
+ *        }
+ *      }
+ *      ngModel.$formatters.push(formatter);
+ *      
+ * + * @property {Array.} $viewChangeListeners Array of functions to execute whenever the + * view value has changed. It is called with no arguments, and its return value is ignored. + * This can be used in place of additional $watches against the model value. + * + * @property {Object} $error An object hash with all errors as keys. + * + * @property {boolean} $pristine True if user has not interacted with the control yet. + * @property {boolean} $dirty True if user has already interacted with the control. + * @property {boolean} $valid True if there is no error. + * @property {boolean} $invalid True if at least one error on the control. + * + * @description + * + * `NgModelController` provides API for the `ng-model` directive. The controller contains + * services for data-binding, validation, CSS updates, and value formatting and parsing. It + * purposefully does not contain any logic which deals with DOM rendering or listening to + * DOM events. Such DOM related logic should be provided by other directives which make use of + * `NgModelController` for data-binding. + * + * ## Custom Control Example + * This example shows how to use `NgModelController` with a custom control to achieve + * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`) + * collaborate together to achieve the desired result. + * + * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element + * contents be edited in place by the user. This will not work on older browsers. + * + * + + [contenteditable] { + border: 1px solid black; + background-color: white; + min-height: 20px; + } + + .ng-invalid { + border: 1px solid red; + } + + + + angular.module('customControl', []). + directive('contenteditable', function() { + return { + restrict: 'A', // only activate on element attribute + require: '?ngModel', // get a hold of NgModelController + link: function(scope, element, attrs, ngModel) { + if(!ngModel) return; // do nothing if no ng-model + + // Specify how UI should be updated + ngModel.$render = function() { + element.html(ngModel.$viewValue || ''); + }; + + // Listen for change events to enable binding + element.on('blur keyup change', function() { + scope.$apply(read); + }); + read(); // initialize + + // Write data to the model + function read() { + var html = element.html(); + // When we clear the content editable the browser leaves a
behind + // If strip-br attribute is provided then we strip this out + if( attrs.stripBr && html == '
' ) { + html = ''; + } + ngModel.$setViewValue(html); + } + } + }; + }); +
+ +
+
Change me!
+ Required! +
+ +
+
+ + it('should data-bind and become invalid', function() { + var contentEditable = element('[contenteditable]'); + + expect(contentEditable.text()).toEqual('Change me!'); + input('userContent').enter(''); + expect(contentEditable.text()).toEqual(''); + expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/); + }); + + *
+ * + * ## Isolated Scope Pitfall + * + * Note that if you have a directive with an isolated scope, you cannot require `ngModel` + * since the model value will be looked up on the isolated scope rather than the outer scope. + * When the directive updates the model value, calling `ngModel.$setViewValue()` the property + * on the outer scope will not be updated. However you can get around this by using $parent. + * + * Here is an example of this situation. You'll notice that the first div is not updating the input. + * However the second div can update the input properly. + * + * + + angular.module('badIsolatedDirective', []).directive('isolate', function() { + return { + require: 'ngModel', + scope: { }, + template: '', + link: function(scope, element, attrs, ngModel) { + scope.$watch('innerModel', function(value) { + console.log(value); + ngModel.$setViewValue(value); + }); + } + }; + }); + + + +
+
+
+ *
+ * + * + */ +var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', + function($scope, $exceptionHandler, $attr, $element, $parse) { + this.$viewValue = Number.NaN; + this.$modelValue = Number.NaN; + this.$parsers = []; + this.$formatters = []; + this.$viewChangeListeners = []; + this.$pristine = true; + this.$dirty = false; + this.$valid = true; + this.$invalid = false; + this.$name = $attr.name; + + var ngModelGet = $parse($attr.ngModel), + ngModelSet = ngModelGet.assign; + + if (!ngModelSet) { + throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}", + $attr.ngModel, startingTag($element)); + } + + /** + * @ngdoc function + * @name ng.directive:ngModel.NgModelController#$render + * @methodOf ng.directive:ngModel.NgModelController + * + * @description + * Called when the view needs to be updated. It is expected that the user of the ng-model + * directive will implement this method. + */ + this.$render = noop; + + /** + * @ngdoc function + * @name { ng.directive:ngModel.NgModelController#$isEmpty + * @methodOf ng.directive:ngModel.NgModelController + * + * @description + * This is called when we need to determine if the value of the input is empty. + * + * For instance, the required directive does this to work out if the input has data or not. + * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`. + * + * You can override this for input directives whose concept of being empty is different to the + * default. The `checkboxInputType` directive does this because in its case a value of `false` + * implies empty. + */ + this.$isEmpty = function(value) { + return isUndefined(value) || value === '' || value === null || value !== value; + }; + + var parentForm = $element.inheritedData('$formController') || nullFormCtrl, + invalidCount = 0, // used to easily determine if we are valid + $error = this.$error = {}; // keep invalid keys here + + + // Setup initial state of the control + $element.addClass(PRISTINE_CLASS); + toggleValidCss(true); + + // convenience method for easy toggling of classes + function toggleValidCss(isValid, validationErrorKey) { + validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : ''; + $element. + removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey). + addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey); + } + + /** + * @ngdoc function + * @name ng.directive:ngModel.NgModelController#$setValidity + * @methodOf ng.directive:ngModel.NgModelController + * + * @description + * Change the validity state, and notifies the form when the control changes validity. (i.e. it + * does not notify form if given validator is already marked as invalid). + * + * This method should be called by validators - i.e. the parser or formatter functions. + * + * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign + * to `$error[validationErrorKey]=isValid` so that it is available for data-binding. + * The `validationErrorKey` should be in camelCase and will get converted into dash-case + * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error` + * class and can be bound to as `{{someForm.someControl.$error.myError}}` . + * @param {boolean} isValid Whether the current state is valid (true) or invalid (false). + */ + this.$setValidity = function(validationErrorKey, isValid) { + // Purposeful use of ! here to cast isValid to boolean in case it is undefined + // jshint -W018 + if ($error[validationErrorKey] === !isValid) return; + // jshint +W018 + + if (isValid) { + if ($error[validationErrorKey]) invalidCount--; + if (!invalidCount) { + toggleValidCss(true); + this.$valid = true; + this.$invalid = false; + } + } else { + toggleValidCss(false); + this.$invalid = true; + this.$valid = false; + invalidCount++; + } + + $error[validationErrorKey] = !isValid; + toggleValidCss(isValid, validationErrorKey); + + parentForm.$setValidity(validationErrorKey, isValid, this); + }; + + /** + * @ngdoc function + * @name ng.directive:ngModel.NgModelController#$setPristine + * @methodOf ng.directive:ngModel.NgModelController + * + * @description + * Sets the control to its pristine state. + * + * This method can be called to remove the 'ng-dirty' class and set the control to its pristine + * state (ng-pristine class). + */ + this.$setPristine = function () { + this.$dirty = false; + this.$pristine = true; + $element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS); + }; + + /** + * @ngdoc function + * @name ng.directive:ngModel.NgModelController#$setViewValue + * @methodOf ng.directive:ngModel.NgModelController + * + * @description + * Update the view value. + * + * This method should be called when the view value changes, typically from within a DOM event handler. + * For example {@link ng.directive:input input} and + * {@link ng.directive:select select} directives call it. + * + * It will update the $viewValue, then pass this value through each of the functions in `$parsers`, + * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to + * `$modelValue` and the **expression** specified in the `ng-model` attribute. + * + * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called. + * + * Note that calling this function does not trigger a `$digest`. + * + * @param {string} value Value from the view. + */ + this.$setViewValue = function(value) { + this.$viewValue = value; + + // change to dirty + if (this.$pristine) { + this.$dirty = true; + this.$pristine = false; + $element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS); + parentForm.$setDirty(); + } + + forEach(this.$parsers, function(fn) { + value = fn(value); + }); + + if (this.$modelValue !== value) { + this.$modelValue = value; + ngModelSet($scope, value); + forEach(this.$viewChangeListeners, function(listener) { + try { + listener(); + } catch(e) { + $exceptionHandler(e); + } + }); + } + }; + + // model -> value + var ctrl = this; + + $scope.$watch(function ngModelWatch() { + var value = ngModelGet($scope); + + // if scope model value and ngModel value are out of sync + if (ctrl.$modelValue !== value) { + + var formatters = ctrl.$formatters, + idx = formatters.length; + + ctrl.$modelValue = value; + while(idx--) { + value = formatters[idx](value); + } + + if (ctrl.$viewValue !== value) { + ctrl.$viewValue = value; + ctrl.$render(); + } + } + }); +}]; + + +/** + * @ngdoc directive + * @name ng.directive:ngModel + * + * @element input + * + * @description + * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a + * property on the scope using {@link ng.directive:ngModel.NgModelController NgModelController}, + * which is created and exposed by this directive. + * + * `ngModel` is responsible for: + * + * - Binding the view into the model, which other directives such as `input`, `textarea` or `select` + * require. + * - Providing validation behavior (i.e. required, number, email, url). + * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors). + * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`). + * - Registering the control with its parent {@link ng.directive:form form}. + * + * Note: `ngModel` will try to bind to the property given by evaluating the expression on the + * current scope. If the property doesn't already exist on this scope, it will be created + * implicitly and added to the scope. + * + * For best practices on using `ngModel`, see: + * + * - {@link https://github.com/angular/angular.js/wiki/Understanding-Scopes} + * + * For basic examples, how to use `ngModel`, see: + * + * - {@link ng.directive:input input} + * - {@link ng.directive:input.text text} + * - {@link ng.directive:input.checkbox checkbox} + * - {@link ng.directive:input.radio radio} + * - {@link ng.directive:input.number number} + * - {@link ng.directive:input.email email} + * - {@link ng.directive:input.url url} + * - {@link ng.directive:select select} + * - {@link ng.directive:textarea textarea} + * + */ +var ngModelDirective = function() { + return { + require: ['ngModel', '^?form'], + controller: NgModelController, + link: function(scope, element, attr, ctrls) { + // notify others, especially parent forms + + var modelCtrl = ctrls[0], + formCtrl = ctrls[1] || nullFormCtrl; + + formCtrl.$addControl(modelCtrl); + + scope.$on('$destroy', function() { + formCtrl.$removeControl(modelCtrl); + }); + } + }; +}; + + +/** + * @ngdoc directive + * @name ng.directive:ngChange + * + * @description + * Evaluate given expression when user changes the input. + * The expression is not evaluated when the value change is coming from the model. + * + * Note, this directive requires `ngModel` to be present. + * + * @element input + * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change + * in input value. + * + * @example + * + * + * + *
+ * + * + *
+ * debug = {{confirmed}}
+ * counter = {{counter}} + *
+ *
+ * + * it('should evaluate the expression if changing from view', function() { + * expect(binding('counter')).toEqual('0'); + * element('#ng-change-example1').click(); + * expect(binding('counter')).toEqual('1'); + * expect(binding('confirmed')).toEqual('true'); + * }); + * + * it('should not evaluate the expression if changing from model', function() { + * element('#ng-change-example2').click(); + * expect(binding('counter')).toEqual('0'); + * expect(binding('confirmed')).toEqual('true'); + * }); + * + *
+ */ +var ngChangeDirective = valueFn({ + require: 'ngModel', + link: function(scope, element, attr, ctrl) { + ctrl.$viewChangeListeners.push(function() { + scope.$eval(attr.ngChange); + }); + } +}); + + +var requiredDirective = function() { + return { + require: '?ngModel', + link: function(scope, elm, attr, ctrl) { + if (!ctrl) return; + attr.required = true; // force truthy in case we are on non input element + + var validator = function(value) { + if (attr.required && ctrl.$isEmpty(value)) { + ctrl.$setValidity('required', false); + return; + } else { + ctrl.$setValidity('required', true); + return value; + } + }; + + ctrl.$formatters.push(validator); + ctrl.$parsers.unshift(validator); + + attr.$observe('required', function() { + validator(ctrl.$viewValue); + }); + } + }; +}; + + +/** + * @ngdoc directive + * @name ng.directive:ngList + * + * @description + * Text input that converts between a delimited string and an array of strings. The delimiter + * can be a fixed string (by default a comma) or a regular expression. + * + * @element input + * @param {string=} ngList optional delimiter that should be used to split the value. If + * specified in form `/something/` then the value will be converted into a regular expression. + * + * @example + + + +
+ List: + + Required! +
+ names = {{names}}
+ myForm.namesInput.$valid = {{myForm.namesInput.$valid}}
+ myForm.namesInput.$error = {{myForm.namesInput.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+
+
+ + it('should initialize to model', function() { + expect(binding('names')).toEqual('["igor","misko","vojta"]'); + expect(binding('myForm.namesInput.$valid')).toEqual('true'); + expect(element('span.error').css('display')).toBe('none'); + }); + + it('should be invalid if empty', function() { + input('names').enter(''); + expect(binding('names')).toEqual(''); + expect(binding('myForm.namesInput.$valid')).toEqual('false'); + expect(element('span.error').css('display')).not().toBe('none'); + }); + +
+ */ +var ngListDirective = function() { + return { + require: 'ngModel', + link: function(scope, element, attr, ctrl) { + var match = /\/(.*)\//.exec(attr.ngList), + separator = match && new RegExp(match[1]) || attr.ngList || ','; + + var parse = function(viewValue) { + // If the viewValue is invalid (say required but empty) it will be `undefined` + if (isUndefined(viewValue)) return; + + var list = []; + + if (viewValue) { + forEach(viewValue.split(separator), function(value) { + if (value) list.push(trim(value)); + }); + } + + return list; + }; + + ctrl.$parsers.push(parse); + ctrl.$formatters.push(function(value) { + if (isArray(value)) { + return value.join(', '); + } + + return undefined; + }); + + // Override the standard $isEmpty because an empty array means the input is empty. + ctrl.$isEmpty = function(value) { + return !value || !value.length; + }; + } + }; +}; + + +var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/; +/** + * @ngdoc directive + * @name ng.directive:ngValue + * + * @description + * Binds the given expression to the value of `input[select]` or `input[radio]`, so + * that when the element is selected, the `ngModel` of that element is set to the + * bound value. + * + * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as + * shown below. + * + * @element input + * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute + * of the `input` element + * + * @example + + + +
+

Which is your favorite?

+ + +
You chose {{my.favorite}}
+
+
+ + it('should initialize to model', function() { + expect(binding('my.favorite')).toEqual('unicorns'); + }); + it('should bind the values to the inputs', function() { + input('my.favorite').select('pizza'); + expect(binding('my.favorite')).toEqual('pizza'); + }); + +
+ */ +var ngValueDirective = function() { + return { + priority: 100, + compile: function(tpl, tplAttr) { + if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) { + return function ngValueConstantLink(scope, elm, attr) { + attr.$set('value', scope.$eval(attr.ngValue)); + }; + } else { + return function ngValueLink(scope, elm, attr) { + scope.$watch(attr.ngValue, function valueWatchAction(value) { + attr.$set('value', value); + }); + }; + } + } + }; +}; + +/** + * @ngdoc directive + * @name ng.directive:ngBind + * @restrict AC + * + * @description + * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element + * with the value of a given expression, and to update the text content when the value of that + * expression changes. + * + * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like + * `{{ expression }}` which is similar but less verbose. + * + * It is preferrable to use `ngBind` instead of `{{ expression }}` when a template is momentarily + * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an + * element attribute, it makes the bindings invisible to the user while the page is loading. + * + * An alternative solution to this problem would be using the + * {@link ng.directive:ngCloak ngCloak} directive. + * + * + * @element ANY + * @param {expression} ngBind {@link guide/expression Expression} to evaluate. + * + * @example + * Enter a name in the Live Preview text box; the greeting below the text box changes instantly. + + + +
+ Enter name:
+ Hello ! +
+
+ + it('should check ng-bind', function() { + expect(using('.doc-example-live').binding('name')).toBe('Whirled'); + using('.doc-example-live').input('name').enter('world'); + expect(using('.doc-example-live').binding('name')).toBe('world'); + }); + +
+ */ +var ngBindDirective = ngDirective(function(scope, element, attr) { + element.addClass('ng-binding').data('$binding', attr.ngBind); + scope.$watch(attr.ngBind, function ngBindWatchAction(value) { + // We are purposefully using == here rather than === because we want to + // catch when value is "null or undefined" + // jshint -W041 + element.text(value == undefined ? '' : value); + }); +}); + + +/** + * @ngdoc directive + * @name ng.directive:ngBindTemplate + * + * @description + * The `ngBindTemplate` directive specifies that the element + * text content should be replaced with the interpolation of the template + * in the `ngBindTemplate` attribute. + * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}` + * expressions. This directive is needed since some HTML elements + * (such as TITLE and OPTION) cannot contain SPAN elements. + * + * @element ANY + * @param {string} ngBindTemplate template of form + * {{ expression }} to eval. + * + * @example + * Try it here: enter text in text box and watch the greeting change. + + + +
+ Salutation:
+ Name:
+

+       
+
+ + it('should check ng-bind', function() { + expect(using('.doc-example-live').binding('salutation')). + toBe('Hello'); + expect(using('.doc-example-live').binding('name')). + toBe('World'); + using('.doc-example-live').input('salutation').enter('Greetings'); + using('.doc-example-live').input('name').enter('user'); + expect(using('.doc-example-live').binding('salutation')). + toBe('Greetings'); + expect(using('.doc-example-live').binding('name')). + toBe('user'); + }); + +
+ */ +var ngBindTemplateDirective = ['$interpolate', function($interpolate) { + return function(scope, element, attr) { + // TODO: move this to scenario runner + var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate)); + element.addClass('ng-binding').data('$binding', interpolateFn); + attr.$observe('ngBindTemplate', function(value) { + element.text(value); + }); + }; +}]; + + +/** + * @ngdoc directive + * @name ng.directive:ngBindHtml + * + * @description + * Creates a binding that will innerHTML the result of evaluating the `expression` into the current + * element in a secure way. By default, the innerHTML-ed content will be sanitized using the {@link + * ngSanitize.$sanitize $sanitize} service. To utilize this functionality, ensure that `$sanitize` + * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in + * core Angular.) You may also bypass sanitization for values you know are safe. To do so, bind to + * an explicitly trusted value via {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}. See the example + * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}. + * + * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you + * will have an exception (instead of an exploit.) + * + * @element ANY + * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate. + * + * @example + Try it here: enter text in text box and watch the greeting change. + + + +
+

+
+
+ + + angular.module('ngBindHtmlExample', ['ngSanitize']) + + .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) { + $scope.myHTML = + 'I am an HTMLstring with links! and other stuff'; + }]); + + + + it('should check ng-bind-html', function() { + expect(using('.doc-example-live').binding('myHTML')). + toBe( + 'I am an HTMLstring with links! and other stuff' + ); + }); + +
+ */ +var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) { + return function(scope, element, attr) { + element.addClass('ng-binding').data('$binding', attr.ngBindHtml); + + var parsed = $parse(attr.ngBindHtml); + function getStringValue() { return (parsed(scope) || '').toString(); } + + scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) { + element.html($sce.getTrustedHtml(parsed(scope)) || ''); + }); + }; +}]; + +function classDirective(name, selector) { + name = 'ngClass' + name; + return function() { + return { + restrict: 'AC', + link: function(scope, element, attr) { + var oldVal; + + scope.$watch(attr[name], ngClassWatchAction, true); + + attr.$observe('class', function(value) { + ngClassWatchAction(scope.$eval(attr[name])); + }); + + + if (name !== 'ngClass') { + scope.$watch('$index', function($index, old$index) { + // jshint bitwise: false + var mod = $index & 1; + if (mod !== old$index & 1) { + var classes = flattenClasses(scope.$eval(attr[name])); + mod === selector ? + attr.$addClass(classes) : + attr.$removeClass(classes); + } + }); + } + + + function ngClassWatchAction(newVal) { + if (selector === true || scope.$index % 2 === selector) { + var newClasses = flattenClasses(newVal || ''); + if(!oldVal) { + attr.$addClass(newClasses); + } else if(!equals(newVal,oldVal)) { + attr.$updateClass(newClasses, flattenClasses(oldVal)); + } + } + oldVal = copy(newVal); + } + + + function flattenClasses(classVal) { + if(isArray(classVal)) { + return classVal.join(' '); + } else if (isObject(classVal)) { + var classes = [], i = 0; + forEach(classVal, function(v, k) { + if (v) { + classes.push(k); + } + }); + return classes.join(' '); + } + + return classVal; + } + } + }; + }; +} + +/** + * @ngdoc directive + * @name ng.directive:ngClass + * @restrict AC + * + * @description + * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding + * an expression that represents all classes to be added. + * + * The directive won't add duplicate classes if a particular class was already set. + * + * When the expression changes, the previously added classes are removed and only then the + * new classes are added. + * + * @animations + * add - happens just before the class is applied to the element + * remove - happens just before the class is removed from the element + * + * @element ANY + * @param {expression} ngClass {@link guide/expression Expression} to eval. The result + * of the evaluation can be a string representing space delimited class + * names, an array, or a map of class names to boolean values. In the case of a map, the + * names of the properties whose values are truthy will be added as css classes to the + * element. + * + * @example Example that demonstrates basic bindings via ngClass directive. + + +

Map Syntax Example

+ deleted (apply "strike" class)
+ important (apply "bold" class)
+ error (apply "red" class) +
+

Using String Syntax

+ +
+

Using Array Syntax

+
+
+
+
+ + .strike { + text-decoration: line-through; + } + .bold { + font-weight: bold; + } + .red { + color: red; + } + + + it('should let you toggle the class', function() { + + expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/); + expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/); + + input('important').check(); + expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/); + + input('error').check(); + expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/); + }); + + it('should let you toggle string example', function() { + expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe(''); + input('style').enter('red'); + expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('red'); + }); + + it('array example should have 3 classes', function() { + expect(element('.doc-example-live p:last').prop('className')).toBe(''); + input('style1').enter('bold'); + input('style2').enter('strike'); + input('style3').enter('red'); + expect(element('.doc-example-live p:last').prop('className')).toBe('bold strike red'); + }); + +
+ + ## Animations + + The example below demonstrates how to perform animations using ngClass. + + + + + +
+ Sample Text +
+ + .base-class { + -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; + transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; + } + + .base-class.my-class { + color: red; + font-size:3em; + } + + + it('should check ng-class', function() { + expect(element('.doc-example-live span').prop('className')).not(). + toMatch(/my-class/); + + using('.doc-example-live').element(':button:first').click(); + + expect(element('.doc-example-live span').prop('className')). + toMatch(/my-class/); + + using('.doc-example-live').element(':button:last').click(); + + expect(element('.doc-example-live span').prop('className')).not(). + toMatch(/my-class/); + }); + +
+ + + ## ngClass and pre-existing CSS3 Transitions/Animations + The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure. + Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder + any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure + to view the step by step details of {@link ngAnimate.$animate#methods_addclass $animate.addClass} and + {@link ngAnimate.$animate#methods_removeclass $animate.removeClass}. + */ +var ngClassDirective = classDirective('', true); + +/** + * @ngdoc directive + * @name ng.directive:ngClassOdd + * @restrict AC + * + * @description + * The `ngClassOdd` and `ngClassEven` directives work exactly as + * {@link ng.directive:ngClass ngClass}, except they work in + * conjunction with `ngRepeat` and take effect only on odd (even) rows. + * + * This directive can be applied only within the scope of an + * {@link ng.directive:ngRepeat ngRepeat}. + * + * @element ANY + * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result + * of the evaluation can be a string representing space delimited class names or an array. + * + * @example + + +
    +
  1. + + {{name}} + +
  2. +
+
+ + .odd { + color: red; + } + .even { + color: blue; + } + + + it('should check ng-class-odd and ng-class-even', function() { + expect(element('.doc-example-live li:first span').prop('className')). + toMatch(/odd/); + expect(element('.doc-example-live li:last span').prop('className')). + toMatch(/even/); + }); + +
+ */ +var ngClassOddDirective = classDirective('Odd', 0); + +/** + * @ngdoc directive + * @name ng.directive:ngClassEven + * @restrict AC + * + * @description + * The `ngClassOdd` and `ngClassEven` directives work exactly as + * {@link ng.directive:ngClass ngClass}, except they work in + * conjunction with `ngRepeat` and take effect only on odd (even) rows. + * + * This directive can be applied only within the scope of an + * {@link ng.directive:ngRepeat ngRepeat}. + * + * @element ANY + * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The + * result of the evaluation can be a string representing space delimited class names or an array. + * + * @example + + +
    +
  1. + + {{name}}       + +
  2. +
+
+ + .odd { + color: red; + } + .even { + color: blue; + } + + + it('should check ng-class-odd and ng-class-even', function() { + expect(element('.doc-example-live li:first span').prop('className')). + toMatch(/odd/); + expect(element('.doc-example-live li:last span').prop('className')). + toMatch(/even/); + }); + +
+ */ +var ngClassEvenDirective = classDirective('Even', 1); + +/** + * @ngdoc directive + * @name ng.directive:ngCloak + * @restrict AC + * + * @description + * The `ngCloak` directive is used to prevent the Angular html template from being briefly + * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this + * directive to avoid the undesirable flicker effect caused by the html template display. + * + * The directive can be applied to the `` element, but the preferred usage is to apply + * multiple `ngCloak` directives to small portions of the page to permit progressive rendering + * of the browser view. + * + * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and + * `angular.min.js`. + * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}). + * + *
+ * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
+ *   display: none !important;
+ * }
+ * 
+ * + * When this css rule is loaded by the browser, all html elements (including their children) that + * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive + * during the compilation of the template it deletes the `ngCloak` element attribute, making + * the compiled element visible. + * + * For the best result, the `angular.js` script must be loaded in the head section of the html + * document; alternatively, the css rule above must be included in the external stylesheet of the + * application. + * + * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they + * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css + * class `ngCloak` in addition to the `ngCloak` directive as shown in the example below. + * + * @element ANY + * + * @example + + +
{{ 'hello' }}
+
{{ 'hello IE7' }}
+
+ + it('should remove the template directive and css class', function() { + expect(element('.doc-example-live #template1').attr('ng-cloak')). + not().toBeDefined(); + expect(element('.doc-example-live #template2').attr('ng-cloak')). + not().toBeDefined(); + }); + +
+ * + */ +var ngCloakDirective = ngDirective({ + compile: function(element, attr) { + attr.$set('ngCloak', undefined); + element.removeClass('ng-cloak'); + } +}); + +/** + * @ngdoc directive + * @name ng.directive:ngController + * + * @description + * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular + * supports the principles behind the Model-View-Controller design pattern. + * + * MVC components in angular: + * + * * Model — The Model is scope properties; scopes are attached to the DOM where scope properties + * are accessed through bindings. + * * View — The template (HTML with data bindings) that is rendered into the View. + * * Controller — The `ngController` directive specifies a Controller class; the class contains business + * logic behind the application to decorate the scope with functions and values + * + * Note that you can also attach controllers to the DOM by declaring it in a route definition + * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller + * again using `ng-controller` in the template itself. This will cause the controller to be attached + * and executed twice. + * + * @element ANY + * @scope + * @param {expression} ngController Name of a globally accessible constructor function or an + * {@link guide/expression expression} that on the current scope evaluates to a + * constructor function. The controller instance can be published into a scope property + * by specifying `as propertyName`. + * + * @example + * Here is a simple form for editing user contact information. Adding, removing, clearing, and + * greeting are methods declared on the controller (see source tab). These methods can + * easily be called from the angular markup. Notice that the scope becomes the `this` for the + * controller's instance. This allows for easy access to the view data from the controller. Also + * notice that any changes to the data are automatically reflected in the View without the need + * for a manual update. The example is shown in two different declaration styles you may use + * according to preference. + + + +
+ Name: + [ greet ]
+ Contact: +
    +
  • + + + [ clear + | X ] +
  • +
  • [ add ]
  • +
+
+
+ + it('should check controller as', function() { + expect(element('#ctrl-as-exmpl>:input').val()).toBe('John Smith'); + expect(element('#ctrl-as-exmpl li:nth-child(1) input').val()) + .toBe('408 555 1212'); + expect(element('#ctrl-as-exmpl li:nth-child(2) input').val()) + .toBe('john.smith@example.org'); + + element('#ctrl-as-exmpl li:first a:contains("clear")').click(); + expect(element('#ctrl-as-exmpl li:first input').val()).toBe(''); + + element('#ctrl-as-exmpl li:last a:contains("add")').click(); + expect(element('#ctrl-as-exmpl li:nth-child(3) input').val()) + .toBe('yourname@example.org'); + }); + +
+ + + +
+ Name: + [ greet ]
+ Contact: +
    +
  • + + + [ clear + | X ] +
  • +
  • [ add ]
  • +
+
+
+ + it('should check controller', function() { + expect(element('#ctrl-exmpl>:input').val()).toBe('John Smith'); + expect(element('#ctrl-exmpl li:nth-child(1) input').val()) + .toBe('408 555 1212'); + expect(element('#ctrl-exmpl li:nth-child(2) input').val()) + .toBe('john.smith@example.org'); + + element('#ctrl-exmpl li:first a:contains("clear")').click(); + expect(element('#ctrl-exmpl li:first input').val()).toBe(''); + + element('#ctrl-exmpl li:last a:contains("add")').click(); + expect(element('#ctrl-exmpl li:nth-child(3) input').val()) + .toBe('yourname@example.org'); + }); + +
+ + */ +var ngControllerDirective = [function() { + return { + scope: true, + controller: '@', + priority: 500 + }; +}]; + +/** + * @ngdoc directive + * @name ng.directive:ngCsp + * + * @element html + * @description + * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support. + * + * This is necessary when developing things like Google Chrome Extensions. + * + * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things). + * For us to be compatible, we just need to implement the "getterFn" in $parse without violating + * any of these restrictions. + * + * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp` + * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will + * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will + * be raised. + * + * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically + * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}). + * To make those directives work in CSP mode, include the `angular-csp.css` manually. + * + * In order to use this feature put the `ngCsp` directive on the root element of the application. + * + * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.* + * + * @example + * This example shows how to apply the `ngCsp` directive to the `html` tag. +
+     
+     
+     ...
+     ...
+     
+   
+ */ + +// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap +// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute +// anywhere in the current doc + +/** + * @ngdoc directive + * @name ng.directive:ngClick + * + * @description + * The ngClick directive allows you to specify custom behavior when + * an element is clicked. + * + * @element ANY + * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon + * click. (Event object is available as `$event`) + * + * @example + + + + count: {{count}} + + + it('should check ng-click', function() { + expect(binding('count')).toBe('0'); + element('.doc-example-live :button').click(); + expect(binding('count')).toBe('1'); + }); + + + */ +/* + * A directive that allows creation of custom onclick handlers that are defined as angular + * expressions and are compiled and executed within the current scope. + * + * Events that are handled via these handler are always configured not to propagate further. + */ +var ngEventDirectives = {}; +forEach( + 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '), + function(name) { + var directiveName = directiveNormalize('ng-' + name); + ngEventDirectives[directiveName] = ['$parse', function($parse) { + return { + compile: function($element, attr) { + var fn = $parse(attr[directiveName]); + return function(scope, element, attr) { + element.on(lowercase(name), function(event) { + scope.$apply(function() { + fn(scope, {$event:event}); + }); + }); + }; + } + }; + }]; + } +); + +/** + * @ngdoc directive + * @name ng.directive:ngDblclick + * + * @description + * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event. + * + * @element ANY + * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon + * a dblclick. (The Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngMousedown + * + * @description + * The ngMousedown directive allows you to specify custom behavior on mousedown event. + * + * @element ANY + * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon + * mousedown. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngMouseup + * + * @description + * Specify custom behavior on mouseup event. + * + * @element ANY + * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon + * mouseup. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + +/** + * @ngdoc directive + * @name ng.directive:ngMouseover + * + * @description + * Specify custom behavior on mouseover event. + * + * @element ANY + * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon + * mouseover. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngMouseenter + * + * @description + * Specify custom behavior on mouseenter event. + * + * @element ANY + * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon + * mouseenter. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngMouseleave + * + * @description + * Specify custom behavior on mouseleave event. + * + * @element ANY + * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon + * mouseleave. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngMousemove + * + * @description + * Specify custom behavior on mousemove event. + * + * @element ANY + * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon + * mousemove. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngKeydown + * + * @description + * Specify custom behavior on keydown event. + * + * @element ANY + * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon + * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngKeyup + * + * @description + * Specify custom behavior on keyup event. + * + * @element ANY + * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon + * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngKeypress + * + * @description + * Specify custom behavior on keypress event. + * + * @element ANY + * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon + * keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + + +/** + * @ngdoc directive + * @name ng.directive:ngSubmit + * + * @description + * Enables binding angular expressions to onsubmit events. + * + * Additionally it prevents the default action (which for form means sending the request to the + * server and reloading the current page) **but only if the form does not contain an `action` + * attribute**. + * + * @element form + * @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`) + * + * @example + + + +
+ Enter text and hit enter: + + +
list={{list}}
+
+
+ + it('should check ng-submit', function() { + expect(binding('list')).toBe('[]'); + element('.doc-example-live #submit').click(); + expect(binding('list')).toBe('["hello"]'); + expect(input('text').val()).toBe(''); + }); + it('should ignore empty strings', function() { + expect(binding('list')).toBe('[]'); + element('.doc-example-live #submit').click(); + element('.doc-example-live #submit').click(); + expect(binding('list')).toBe('["hello"]'); + }); + +
+ */ + +/** + * @ngdoc directive + * @name ng.directive:ngFocus + * + * @description + * Specify custom behavior on focus event. + * + * @element window, input, select, textarea, a + * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon + * focus. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + +/** + * @ngdoc directive + * @name ng.directive:ngBlur + * + * @description + * Specify custom behavior on blur event. + * + * @element window, input, select, textarea, a + * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon + * blur. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + +/** + * @ngdoc directive + * @name ng.directive:ngCopy + * + * @description + * Specify custom behavior on copy event. + * + * @element window, input, select, textarea, a + * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon + * copy. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + +/** + * @ngdoc directive + * @name ng.directive:ngCut + * + * @description + * Specify custom behavior on cut event. + * + * @element window, input, select, textarea, a + * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon + * cut. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + +/** + * @ngdoc directive + * @name ng.directive:ngPaste + * + * @description + * Specify custom behavior on paste event. + * + * @element window, input, select, textarea, a + * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon + * paste. (Event object is available as `$event`) + * + * @example + * See {@link ng.directive:ngClick ngClick} + */ + +/** + * @ngdoc directive + * @name ng.directive:ngIf + * @restrict A + * + * @description + * The `ngIf` directive removes or recreates a portion of the DOM tree based on an + * {expression}. If the expression assigned to `ngIf` evaluates to a false + * value then the element is removed from the DOM, otherwise a clone of the + * element is reinserted into the DOM. + * + * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the + * element in the DOM rather than changing its visibility via the `display` css property. A common + * case when this difference is significant is when using css selectors that rely on an element's + * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes. + * + * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope + * is created when the element is restored. The scope created within `ngIf` inherits from + * its parent scope using + * {@link https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance prototypal inheritance}. + * An important implication of this is if `ngModel` is used within `ngIf` to bind to + * a javascript primitive defined in the parent scope. In this case any modifications made to the + * variable within the child scope will override (hide) the value in the parent scope. + * + * Also, `ngIf` recreates elements using their compiled state. An example of this behavior + * is if an element's class attribute is directly modified after it's compiled, using something like + * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element + * the added class will be lost because the original compiled state is used to regenerate the element. + * + * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter` + * and `leave` effects. + * + * @animations + * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container + * leave - happens just before the ngIf contents are removed from the DOM + * + * @element ANY + * @scope + * @priority 600 + * @param {expression} ngIf If the {@link guide/expression expression} is falsy then + * the element is removed from the DOM tree. If it is truthy a copy of the compiled + * element is added to the DOM tree. + * + * @example + + + Click me:
+ Show when checked: + + I'm removed when the checkbox is unchecked. + +
+ + .animate-if { + background:white; + border:1px solid black; + padding:10px; + } + + /* + The transition styles can also be placed on the CSS base class above + */ + .animate-if.ng-enter, .animate-if.ng-leave { + -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; + transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; + } + + .animate-if.ng-enter, + .animate-if.ng-leave.ng-leave-active { + opacity:0; + } + + .animate-if.ng-leave, + .animate-if.ng-enter.ng-enter-active { + opacity:1; + } + +
+ */ +var ngIfDirective = ['$animate', function($animate) { + return { + transclude: 'element', + priority: 600, + terminal: true, + restrict: 'A', + $$tlb: true, + link: function ($scope, $element, $attr, ctrl, $transclude) { + var block, childScope; + $scope.$watch($attr.ngIf, function ngIfWatchAction(value) { + + if (toBoolean(value)) { + if (!childScope) { + childScope = $scope.$new(); + $transclude(childScope, function (clone) { + block = { + startNode: clone[0], + endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ') + }; + $animate.enter(clone, $element.parent(), $element); + }); + } + } else { + + if (childScope) { + childScope.$destroy(); + childScope = null; + } + + if (block) { + $animate.leave(getBlockElements(block)); + block = null; + } + } + }); + } + }; +}]; + +/** + * @ngdoc directive + * @name ng.directive:ngInclude + * @restrict ECA + * + * @description + * Fetches, compiles and includes an external HTML fragment. + * + * By default, the template URL is restricted to the same domain and protocol as the + * application document. This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl + * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols + * you may either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist them} or + * {@link ng.$sce#methods_trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link + * ng.$sce Strict Contextual Escaping}. + * + * In addition, the browser's + * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest + * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing + * (CORS)} policy may further restrict whether the template is successfully loaded. + * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://` + * access on some browsers. + * + * @animations + * enter - animation is used to bring new content into the browser. + * leave - animation is used to animate existing content away. + * + * The enter and leave animation occur concurrently. + * + * @scope + * @priority 400 + * + * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant, + * make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`. + * @param {string=} onload Expression to evaluate when a new partial is loaded. + * + * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll + * $anchorScroll} to scroll the viewport after the content is loaded. + * + * - If the attribute is not set, disable scrolling. + * - If the attribute is set without value, enable scrolling. + * - Otherwise enable scrolling only if the expression evaluates to truthy value. + * + * @example + + +
+ + url of the template: {{template.url}} +
+
+
+
+
+
+ + function Ctrl($scope) { + $scope.templates = + [ { name: 'template1.html', url: 'template1.html'} + , { name: 'template2.html', url: 'template2.html'} ]; + $scope.template = $scope.templates[0]; + } + + + Content of template1.html + + + Content of template2.html + + + .slide-animate-container { + position:relative; + background:white; + border:1px solid black; + height:40px; + overflow:hidden; + } + + .slide-animate { + padding:10px; + } + + .slide-animate.ng-enter, .slide-animate.ng-leave { + -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; + transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; + + position:absolute; + top:0; + left:0; + right:0; + bottom:0; + display:block; + padding:10px; + } + + .slide-animate.ng-enter { + top:-50px; + } + .slide-animate.ng-enter.ng-enter-active { + top:0; + } + + .slide-animate.ng-leave { + top:0; + } + .slide-animate.ng-leave.ng-leave-active { + top:50px; + } + + + it('should load template1.html', function() { + expect(element('.doc-example-live [ng-include]').text()). + toMatch(/Content of template1.html/); + }); + it('should load template2.html', function() { + select('template').option('1'); + expect(element('.doc-example-live [ng-include]').text()). + toMatch(/Content of template2.html/); + }); + it('should change to blank', function() { + select('template').option(''); + expect(element('.doc-example-live [ng-include]')).toBe(undefined); + }); + +
+ */ + + +/** + * @ngdoc event + * @name ng.directive:ngInclude#$includeContentRequested + * @eventOf ng.directive:ngInclude + * @eventType emit on the scope ngInclude was declared in + * @description + * Emitted every time the ngInclude content is requested. + */ + + +/** + * @ngdoc event + * @name ng.directive:ngInclude#$includeContentLoaded + * @eventOf ng.directive:ngInclude + * @eventType emit on the current ngInclude scope + * @description + * Emitted every time the ngInclude content is reloaded. + */ +var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animate', '$sce', + function($http, $templateCache, $anchorScroll, $compile, $animate, $sce) { + return { + restrict: 'ECA', + priority: 400, + terminal: true, + transclude: 'element', + compile: function(element, attr) { + var srcExp = attr.ngInclude || attr.src, + onloadExp = attr.onload || '', + autoScrollExp = attr.autoscroll; + + return function(scope, $element, $attr, ctrl, $transclude) { + var changeCounter = 0, + currentScope, + currentElement; + + var cleanupLastIncludeContent = function() { + if (currentScope) { + currentScope.$destroy(); + currentScope = null; + } + if(currentElement) { + $animate.leave(currentElement); + currentElement = null; + } + }; + + scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) { + var afterAnimation = function() { + if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { + $anchorScroll(); + } + }; + var thisChangeId = ++changeCounter; + + if (src) { + $http.get(src, {cache: $templateCache}).success(function(response) { + if (thisChangeId !== changeCounter) return; + var newScope = scope.$new(); + + // Note: This will also link all children of ng-include that were contained in the original + // html. If that content contains controllers, ... they could pollute/change the scope. + // However, using ng-include on an element with additional content does not make sense... + // Note: We can't remove them in the cloneAttchFn of $transclude as that + // function is called before linking the content, which would apply child + // directives to non existing elements. + var clone = $transclude(newScope, noop); + cleanupLastIncludeContent(); + + currentScope = newScope; + currentElement = clone; + + currentElement.html(response); + $animate.enter(currentElement, null, $element, afterAnimation); + $compile(currentElement.contents())(currentScope); + currentScope.$emit('$includeContentLoaded'); + scope.$eval(onloadExp); + }).error(function() { + if (thisChangeId === changeCounter) cleanupLastIncludeContent(); + }); + scope.$emit('$includeContentRequested'); + } else { + cleanupLastIncludeContent(); + } + }); + }; + } + }; +}]; + +/** + * @ngdoc directive + * @name ng.directive:ngInit + * @restrict AC + * + * @description + * The `ngInit` directive allows you to evaluate an expression in the + * current scope. + * + *
+ * The only appropriate use of `ngInit` for aliasing special properties of + * {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you + * should use {@link guide/controller controllers} rather than `ngInit` + * to initialize values on a scope. + *
+ * + * @element ANY + * @param {expression} ngInit {@link guide/expression Expression} to eval. + * + * @example + + + +
+
+
+ list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}}; +
+
+
+
+ + it('should alias index positions', function() { + expect(element('.example-init').text()) + .toBe('list[ 0 ][ 0 ] = a;' + + 'list[ 0 ][ 1 ] = b;' + + 'list[ 1 ][ 0 ] = c;' + + 'list[ 1 ][ 1 ] = d;'); + }); + +
+ */ +var ngInitDirective = ngDirective({ + compile: function() { + return { + pre: function(scope, element, attrs) { + scope.$eval(attrs.ngInit); + } + }; + } +}); + +/** + * @ngdoc directive + * @name ng.directive:ngNonBindable + * @restrict AC + * @priority 1000 + * + * @description + * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current + * DOM element. This is useful if the element contains what appears to be Angular directives and + * bindings but which should be ignored by Angular. This could be the case if you have a site that + * displays snippets of code, for instance. + * + * @element ANY + * + * @example + * In this example there are two locations where a simple interpolation binding (`{{}}`) is present, + * but the one wrapped in `ngNonBindable` is left alone. + * + * @example + + +
Normal: {{1 + 2}}
+
Ignored: {{1 + 2}}
+
+ + it('should check ng-non-bindable', function() { + expect(using('.doc-example-live').binding('1 + 2')).toBe('3'); + expect(using('.doc-example-live').element('div:last').text()). + toMatch(/1 \+ 2/); + }); + +
+ */ +var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 }); + +/** + * @ngdoc directive + * @name ng.directive:ngPluralize + * @restrict EA + * + * @description + * # Overview + * `ngPluralize` is a directive that displays messages according to en-US localization rules. + * These rules are bundled with angular.js, but can be overridden + * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive + * by specifying the mappings between + * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html + * plural categories} and the strings to be displayed. + * + * # Plural categories and explicit number rules + * There are two + * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html + * plural categories} in Angular's default en-US locale: "one" and "other". + * + * While a plural category may match many numbers (for example, in en-US locale, "other" can match + * any number that is not 1), an explicit number rule can only match one number. For example, the + * explicit number rule for "3" matches the number 3. There are examples of plural categories + * and explicit number rules throughout the rest of this documentation. + * + * # Configuring ngPluralize + * You configure ngPluralize by providing 2 attributes: `count` and `when`. + * You can also provide an optional attribute, `offset`. + * + * The value of the `count` attribute can be either a string or an {@link guide/expression + * Angular expression}; these are evaluated on the current scope for its bound value. + * + * The `when` attribute specifies the mappings between plural categories and the actual + * string to be displayed. The value of the attribute should be a JSON object. + * + * The following example shows how to configure ngPluralize: + * + *
+ * 
+ * 
+ *
+ * + * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not + * specify this rule, 0 would be matched to the "other" category and "0 people are viewing" + * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for + * other numbers, for example 12, so that instead of showing "12 people are viewing", you can + * show "a dozen people are viewing". + * + * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted + * into pluralized strings. In the previous example, Angular will replace `{}` with + * `{{personCount}}`. The closed braces `{}` is a placeholder + * for {{numberExpression}}. + * + * # Configuring ngPluralize with offset + * The `offset` attribute allows further customization of pluralized text, which can result in + * a better user experience. For example, instead of the message "4 people are viewing this document", + * you might display "John, Kate and 2 others are viewing this document". + * The offset attribute allows you to offset a number by any desired value. + * Let's take a look at an example: + * + *
+ * 
+ * 
+ * 
+ * + * Notice that we are still using two plural categories(one, other), but we added + * three explicit number rules 0, 1 and 2. + * When one person, perhaps John, views the document, "John is viewing" will be shown. + * When three people view the document, no explicit number rule is found, so + * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category. + * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing" + * is shown. + * + * Note that when you specify offsets, you must provide explicit number rules for + * numbers from 0 up to and including the offset. If you use an offset of 3, for example, + * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for + * plural categories "one" and "other". + * + * @param {string|expression} count The variable to be bounded to. + * @param {string} when The mapping between plural category to its corresponding strings. + * @param {number=} offset Offset to deduct from the total number. + * + * @example + + + +
+ Person 1:
+ Person 2:
+ Number of People:
+ + + Without Offset: + +
+ + + With Offset(2): + + +
+
+ + it('should show correct pluralized string', function() { + expect(element('.doc-example-live ng-pluralize:first').text()). + toBe('1 person is viewing.'); + expect(element('.doc-example-live ng-pluralize:last').text()). + toBe('Igor is viewing.'); + + using('.doc-example-live').input('personCount').enter('0'); + expect(element('.doc-example-live ng-pluralize:first').text()). + toBe('Nobody is viewing.'); + expect(element('.doc-example-live ng-pluralize:last').text()). + toBe('Nobody is viewing.'); + + using('.doc-example-live').input('personCount').enter('2'); + expect(element('.doc-example-live ng-pluralize:first').text()). + toBe('2 people are viewing.'); + expect(element('.doc-example-live ng-pluralize:last').text()). + toBe('Igor and Misko are viewing.'); + + using('.doc-example-live').input('personCount').enter('3'); + expect(element('.doc-example-live ng-pluralize:first').text()). + toBe('3 people are viewing.'); + expect(element('.doc-example-live ng-pluralize:last').text()). + toBe('Igor, Misko and one other person are viewing.'); + + using('.doc-example-live').input('personCount').enter('4'); + expect(element('.doc-example-live ng-pluralize:first').text()). + toBe('4 people are viewing.'); + expect(element('.doc-example-live ng-pluralize:last').text()). + toBe('Igor, Misko and 2 other people are viewing.'); + }); + + it('should show data-binded names', function() { + using('.doc-example-live').input('personCount').enter('4'); + expect(element('.doc-example-live ng-pluralize:last').text()). + toBe('Igor, Misko and 2 other people are viewing.'); + + using('.doc-example-live').input('person1').enter('Di'); + using('.doc-example-live').input('person2').enter('Vojta'); + expect(element('.doc-example-live ng-pluralize:last').text()). + toBe('Di, Vojta and 2 other people are viewing.'); + }); + +
+ */ +var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) { + var BRACE = /{}/g; + return { + restrict: 'EA', + link: function(scope, element, attr) { + var numberExp = attr.count, + whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs + offset = attr.offset || 0, + whens = scope.$eval(whenExp) || {}, + whensExpFns = {}, + startSymbol = $interpolate.startSymbol(), + endSymbol = $interpolate.endSymbol(), + isWhen = /^when(Minus)?(.+)$/; + + forEach(attr, function(expression, attributeName) { + if (isWhen.test(attributeName)) { + whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] = + element.attr(attr.$attr[attributeName]); + } + }); + forEach(whens, function(expression, key) { + whensExpFns[key] = + $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' + + offset + endSymbol)); + }); + + scope.$watch(function ngPluralizeWatch() { + var value = parseFloat(scope.$eval(numberExp)); + + if (!isNaN(value)) { + //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise, + //check it against pluralization rules in $locale service + if (!(value in whens)) value = $locale.pluralCat(value - offset); + return whensExpFns[value](scope, element, true); + } else { + return ''; + } + }, function ngPluralizeWatchAction(newVal) { + element.text(newVal); + }); + } + }; +}]; + +/** + * @ngdoc directive + * @name ng.directive:ngRepeat + * + * @description + * The `ngRepeat` directive instantiates a template once per item from a collection. Each template + * instance gets its own scope, where the given loop variable is set to the current collection item, + * and `$index` is set to the item index or key. + * + * Special properties are exposed on the local scope of each template instance, including: + * + * | Variable | Type | Details | + * |-----------|-----------------|-----------------------------------------------------------------------------| + * | `$index` | {@type number} | iterator offset of the repeated element (0..length-1) | + * | `$first` | {@type boolean} | true if the repeated element is first in the iterator. | + * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. | + * | `$last` | {@type boolean} | true if the repeated element is last in the iterator. | + * | `$even` | {@type boolean} | true if the iterator position `$index` is even (otherwise false). | + * | `$odd` | {@type boolean} | true if the iterator position `$index` is odd (otherwise false). | + * + * + * # Special repeat start and end points + * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending + * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively. + * The **ng-repeat-start** directive works the same as **ng-repeat**, but will repeat all the HTML code (including the tag it's defined on) + * up to and including the ending HTML tag where **ng-repeat-end** is placed. + * + * The example below makes use of this feature: + *
+ *   
+ * Header {{ item }} + *
+ *
+ * Body {{ item }} + *
+ *
+ * Footer {{ item }} + *
+ *
+ * + * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to: + *
+ *   
+ * Header A + *
+ *
+ * Body A + *
+ *
+ * Footer A + *
+ *
+ * Header B + *
+ *
+ * Body B + *
+ *
+ * Footer B + *
+ *
+ * + * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such + * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**). + * + * @animations + * enter - when a new item is added to the list or when an item is revealed after a filter + * leave - when an item is removed from the list or when an item is filtered out + * move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered + * + * @element ANY + * @scope + * @priority 1000 + * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These + * formats are currently supported: + * + * * `variable in expression` – where variable is the user defined loop variable and `expression` + * is a scope expression giving the collection to enumerate. + * + * For example: `album in artist.albums`. + * + * * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers, + * and `expression` is the scope expression giving the collection to enumerate. + * + * For example: `(name, age) in {'adam':10, 'amalie':12}`. + * + * * `variable in expression track by tracking_expression` – You can also provide an optional tracking function + * which can be used to associate the objects in the collection with the DOM elements. If no tracking function + * is specified the ng-repeat associates elements by identity in the collection. It is an error to have + * more than one tracking function to resolve to the same key. (This would mean that two distinct objects are + * mapped to the same DOM element, which is not possible.) Filters should be applied to the expression, + * before specifying a tracking expression. + * + * For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements + * will be associated by item identity in the array. + * + * For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique + * `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements + * with the corresponding item in the array by identity. Moving the same object in array would move the DOM + * element in the same way in the DOM. + * + * For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this + * case the object identity does not matter. Two objects are considered equivalent as long as their `id` + * property is same. + * + * For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter + * to items in conjunction with a tracking expression. + * + * @example + * This example initializes the scope to a list of names and + * then uses `ngRepeat` to display every person: + + +
+ I have {{friends.length}} friends. They are: + +
    +
  • + [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old. +
  • +
+
+
+ + .example-animate-container { + background:white; + border:1px solid black; + list-style:none; + margin:0; + padding:0 10px; + } + + .animate-repeat { + line-height:40px; + list-style:none; + box-sizing:border-box; + } + + .animate-repeat.ng-move, + .animate-repeat.ng-enter, + .animate-repeat.ng-leave { + -webkit-transition:all linear 0.5s; + transition:all linear 0.5s; + } + + .animate-repeat.ng-leave.ng-leave-active, + .animate-repeat.ng-move, + .animate-repeat.ng-enter { + opacity:0; + max-height:0; + } + + .animate-repeat.ng-leave, + .animate-repeat.ng-move.ng-move-active, + .animate-repeat.ng-enter.ng-enter-active { + opacity:1; + max-height:40px; + } + + + it('should render initial data set', function() { + var r = using('.doc-example-live').repeater('ul li'); + expect(r.count()).toBe(10); + expect(r.row(0)).toEqual(["1","John","25"]); + expect(r.row(1)).toEqual(["2","Jessie","30"]); + expect(r.row(9)).toEqual(["10","Samantha","60"]); + expect(binding('friends.length')).toBe("10"); + }); + + it('should update repeater when filter predicate changes', function() { + var r = using('.doc-example-live').repeater('ul li'); + expect(r.count()).toBe(10); + + input('q').enter('ma'); + + expect(r.count()).toBe(2); + expect(r.row(0)).toEqual(["1","Mary","28"]); + expect(r.row(1)).toEqual(["2","Samantha","60"]); + }); + +
+ */ +var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { + var NG_REMOVED = '$$NG_REMOVED'; + var ngRepeatMinErr = minErr('ngRepeat'); + return { + transclude: 'element', + priority: 1000, + terminal: true, + $$tlb: true, + link: function($scope, $element, $attr, ctrl, $transclude){ + var expression = $attr.ngRepeat; + var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/), + trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn, + lhs, rhs, valueIdentifier, keyIdentifier, + hashFnLocals = {$id: hashKey}; + + if (!match) { + throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.", + expression); + } + + lhs = match[1]; + rhs = match[2]; + trackByExp = match[4]; + + if (trackByExp) { + trackByExpGetter = $parse(trackByExp); + trackByIdExpFn = function(key, value, index) { + // assign key, value, and $index to the locals so that they can be used in hash functions + if (keyIdentifier) hashFnLocals[keyIdentifier] = key; + hashFnLocals[valueIdentifier] = value; + hashFnLocals.$index = index; + return trackByExpGetter($scope, hashFnLocals); + }; + } else { + trackByIdArrayFn = function(key, value) { + return hashKey(value); + }; + trackByIdObjFn = function(key) { + return key; + }; + } + + match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/); + if (!match) { + throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.", + lhs); + } + valueIdentifier = match[3] || match[1]; + keyIdentifier = match[2]; + + // Store a list of elements from previous run. This is a hash where key is the item from the + // iterator, and the value is objects with following properties. + // - scope: bound scope + // - element: previous element. + // - index: position + var lastBlockMap = {}; + + //watch props + $scope.$watchCollection(rhs, function ngRepeatAction(collection){ + var index, length, + previousNode = $element[0], // current position of the node + nextNode, + // Same as lastBlockMap but it has the current state. It will become the + // lastBlockMap on the next iteration. + nextBlockMap = {}, + arrayLength, + childScope, + key, value, // key/value of iteration + trackById, + trackByIdFn, + collectionKeys, + block, // last object information {scope, element, id} + nextBlockOrder = [], + elementsToRemove; + + + if (isArrayLike(collection)) { + collectionKeys = collection; + trackByIdFn = trackByIdExpFn || trackByIdArrayFn; + } else { + trackByIdFn = trackByIdExpFn || trackByIdObjFn; + // if object, extract keys, sort them and use to determine order of iteration over obj props + collectionKeys = []; + for (key in collection) { + if (collection.hasOwnProperty(key) && key.charAt(0) != '$') { + collectionKeys.push(key); + } + } + collectionKeys.sort(); + } + + arrayLength = collectionKeys.length; + + // locate existing items + length = nextBlockOrder.length = collectionKeys.length; + for(index = 0; index < length; index++) { + key = (collection === collectionKeys) ? index : collectionKeys[index]; + value = collection[key]; + trackById = trackByIdFn(key, value, index); + assertNotHasOwnProperty(trackById, '`track by` id'); + if(lastBlockMap.hasOwnProperty(trackById)) { + block = lastBlockMap[trackById]; + delete lastBlockMap[trackById]; + nextBlockMap[trackById] = block; + nextBlockOrder[index] = block; + } else if (nextBlockMap.hasOwnProperty(trackById)) { + // restore lastBlockMap + forEach(nextBlockOrder, function(block) { + if (block && block.startNode) lastBlockMap[block.id] = block; + }); + // This is a duplicate and we need to throw an error + throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}", + expression, trackById); + } else { + // new never before seen block + nextBlockOrder[index] = { id: trackById }; + nextBlockMap[trackById] = false; + } + } + + // remove existing items + for (key in lastBlockMap) { + // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn + if (lastBlockMap.hasOwnProperty(key)) { + block = lastBlockMap[key]; + elementsToRemove = getBlockElements(block); + $animate.leave(elementsToRemove); + forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; }); + block.scope.$destroy(); + } + } + + // we are not using forEach for perf reasons (trying to avoid #call) + for (index = 0, length = collectionKeys.length; index < length; index++) { + key = (collection === collectionKeys) ? index : collectionKeys[index]; + value = collection[key]; + block = nextBlockOrder[index]; + if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode; + + if (block.startNode) { + // if we have already seen this object, then we need to reuse the + // associated scope/element + childScope = block.scope; + + nextNode = previousNode; + do { + nextNode = nextNode.nextSibling; + } while(nextNode && nextNode[NG_REMOVED]); + + if (block.startNode != nextNode) { + // existing item which got moved + $animate.move(getBlockElements(block), null, jqLite(previousNode)); + } + previousNode = block.endNode; + } else { + // new item which we don't know about + childScope = $scope.$new(); + } + + childScope[valueIdentifier] = value; + if (keyIdentifier) childScope[keyIdentifier] = key; + childScope.$index = index; + childScope.$first = (index === 0); + childScope.$last = (index === (arrayLength - 1)); + childScope.$middle = !(childScope.$first || childScope.$last); + // jshint bitwise: false + childScope.$odd = !(childScope.$even = (index&1) === 0); + // jshint bitwise: true + + if (!block.startNode) { + $transclude(childScope, function(clone) { + clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' '); + $animate.enter(clone, null, jqLite(previousNode)); + previousNode = clone; + block.scope = childScope; + block.startNode = previousNode && previousNode.endNode ? previousNode.endNode : clone[0]; + block.endNode = clone[clone.length - 1]; + nextBlockMap[block.id] = block; + }); + } + } + lastBlockMap = nextBlockMap; + }); + } + }; +}]; + +/** + * @ngdoc directive + * @name ng.directive:ngShow + * + * @description + * The `ngShow` directive shows or hides the given HTML element based on the expression + * provided to the ngShow attribute. The element is shown or hidden by removing or adding + * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined + * in AngularJS and sets the display style to none (using an !important flag). + * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}). + * + *
+ * 
+ * 
+ * + * + *
+ *
+ * + * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute + * on the element causing it to become hidden. When true, the ng-hide CSS class is removed + * from the element causing the element not to appear hidden. + * + * ## Why is !important used? + * + * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector + * can be easily overridden by heavier selectors. For example, something as simple + * as changing the display style on a HTML list item would make hidden elements appear visible. + * This also becomes a bigger issue when dealing with CSS frameworks. + * + * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector + * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the + * styling to change how to hide an element then it is just a matter of using !important in their own CSS code. + * + * ### Overriding .ng-hide + * + * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by + * restating the styles for the .ng-hide class in CSS: + *
+ * .ng-hide {
+ *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
+ *   display:block!important;
+ *
+ *   //this is just another form of hiding an element
+ *   position:absolute;
+ *   top:-9999px;
+ *   left:-9999px;
+ * }
+ * 
+ * + * Just remember to include the important flag so the CSS override will function. + * + * ## A note about animations with ngShow + * + * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression + * is true and false. This system works like the animation system present with ngClass except that + * you must also include the !important flag to override the display property + * so that you can perform an animation when the element is hidden during the time of the animation. + * + *
+ * //
+ * //a working example can be found at the bottom of this page
+ * //
+ * .my-element.ng-hide-add, .my-element.ng-hide-remove {
+ *   transition:0.5s linear all;
+ *   display:block!important;
+ * }
+ *
+ * .my-element.ng-hide-add { ... }
+ * .my-element.ng-hide-add.ng-hide-add-active { ... }
+ * .my-element.ng-hide-remove { ... }
+ * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
+ * 
+ * + * @animations + * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible + * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden + * + * @element ANY + * @param {expression} ngShow If the {@link guide/expression expression} is truthy + * then the element is shown or hidden respectively. + * + * @example + + + Click me:
+
+ Show: +
+ I show up when your checkbox is checked. +
+
+
+ Hide: +
+ I hide when your checkbox is checked. +
+
+
+ + .animate-show { + -webkit-transition:all linear 0.5s; + transition:all linear 0.5s; + line-height:20px; + opacity:1; + padding:10px; + border:1px solid black; + background:white; + } + + .animate-show.ng-hide-add, + .animate-show.ng-hide-remove { + display:block!important; + } + + .animate-show.ng-hide { + line-height:0; + opacity:0; + padding:0 10px; + } + + .check-element { + padding:10px; + border:1px solid black; + background:white; + } + + + it('should check ng-show / ng-hide', function() { + expect(element('.doc-example-live span:first:hidden').count()).toEqual(1); + expect(element('.doc-example-live span:last:visible').count()).toEqual(1); + + input('checked').check(); + + expect(element('.doc-example-live span:first:visible').count()).toEqual(1); + expect(element('.doc-example-live span:last:hidden').count()).toEqual(1); + }); + +
+ */ +var ngShowDirective = ['$animate', function($animate) { + return function(scope, element, attr) { + scope.$watch(attr.ngShow, function ngShowWatchAction(value){ + $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide'); + }); + }; +}]; + + +/** + * @ngdoc directive + * @name ng.directive:ngHide + * + * @description + * The `ngHide` directive shows or hides the given HTML element based on the expression + * provided to the ngHide attribute. The element is shown or hidden by removing or adding + * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined + * in AngularJS and sets the display style to none (using an !important flag). + * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}). + * + *
+ * 
+ * 
+ * + * + *
+ *
+ * + * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute + * on the element causing it to become hidden. When false, the ng-hide CSS class is removed + * from the element causing the element not to appear hidden. + * + * ## Why is !important used? + * + * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector + * can be easily overridden by heavier selectors. For example, something as simple + * as changing the display style on a HTML list item would make hidden elements appear visible. + * This also becomes a bigger issue when dealing with CSS frameworks. + * + * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector + * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the + * styling to change how to hide an element then it is just a matter of using !important in their own CSS code. + * + * ### Overriding .ng-hide + * + * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by + * restating the styles for the .ng-hide class in CSS: + *
+ * .ng-hide {
+ *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
+ *   display:block!important;
+ *
+ *   //this is just another form of hiding an element
+ *   position:absolute;
+ *   top:-9999px;
+ *   left:-9999px;
+ * }
+ * 
+ * + * Just remember to include the important flag so the CSS override will function. + * + * ## A note about animations with ngHide + * + * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression + * is true and false. This system works like the animation system present with ngClass, except that + * you must also include the !important flag to override the display property so + * that you can perform an animation when the element is hidden during the time of the animation. + * + *
+ * //
+ * //a working example can be found at the bottom of this page
+ * //
+ * .my-element.ng-hide-add, .my-element.ng-hide-remove {
+ *   transition:0.5s linear all;
+ *   display:block!important;
+ * }
+ *
+ * .my-element.ng-hide-add { ... }
+ * .my-element.ng-hide-add.ng-hide-add-active { ... }
+ * .my-element.ng-hide-remove { ... }
+ * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
+ * 
+ * + * @animations + * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden + * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible + * + * @element ANY + * @param {expression} ngHide If the {@link guide/expression expression} is truthy then + * the element is shown or hidden respectively. + * + * @example + + + Click me:
+
+ Show: +
+ I show up when your checkbox is checked. +
+
+
+ Hide: +
+ I hide when your checkbox is checked. +
+
+
+ + .animate-hide { + -webkit-transition:all linear 0.5s; + transition:all linear 0.5s; + line-height:20px; + opacity:1; + padding:10px; + border:1px solid black; + background:white; + } + + .animate-hide.ng-hide-add, + .animate-hide.ng-hide-remove { + display:block!important; + } + + .animate-hide.ng-hide { + line-height:0; + opacity:0; + padding:0 10px; + } + + .check-element { + padding:10px; + border:1px solid black; + background:white; + } + + + it('should check ng-show / ng-hide', function() { + expect(element('.doc-example-live .check-element:first:hidden').count()).toEqual(1); + expect(element('.doc-example-live .check-element:last:visible').count()).toEqual(1); + + input('checked').check(); + + expect(element('.doc-example-live .check-element:first:visible').count()).toEqual(1); + expect(element('.doc-example-live .check-element:last:hidden').count()).toEqual(1); + }); + +
+ */ +var ngHideDirective = ['$animate', function($animate) { + return function(scope, element, attr) { + scope.$watch(attr.ngHide, function ngHideWatchAction(value){ + $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide'); + }); + }; +}]; + +/** + * @ngdoc directive + * @name ng.directive:ngStyle + * @restrict AC + * + * @description + * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally. + * + * @element ANY + * @param {expression} ngStyle {@link guide/expression Expression} which evals to an + * object whose keys are CSS style names and values are corresponding values for those CSS + * keys. + * + * @example + + + + +
+ Sample Text +
myStyle={{myStyle}}
+
+ + span { + color: black; + } + + + it('should check ng-style', function() { + expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)'); + element('.doc-example-live :button[value=set]').click(); + expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)'); + element('.doc-example-live :button[value=clear]').click(); + expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)'); + }); + +
+ */ +var ngStyleDirective = ngDirective(function(scope, element, attr) { + scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) { + if (oldStyles && (newStyles !== oldStyles)) { + forEach(oldStyles, function(val, style) { element.css(style, '');}); + } + if (newStyles) element.css(newStyles); + }, true); +}); + +/** + * @ngdoc directive + * @name ng.directive:ngSwitch + * @restrict EA + * + * @description + * The ngSwitch directive is used to conditionally swap DOM structure on your template based on a scope expression. + * Elements within ngSwitch but without ngSwitchWhen or ngSwitchDefault directives will be preserved at the location + * as specified in the template. + * + * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it + * from the template cache), ngSwitch simply choses one of the nested elements and makes it visible based on which element + * matches the value obtained from the evaluated expression. In other words, you define a container element + * (where you place the directive), place an expression on the **on="..." attribute** + * (or the **ng-switch="..." attribute**), define any inner elements inside of the directive and place + * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on + * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default + * attribute is displayed. + * + * @animations + * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container + * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM + * + * @usage + * + * ... + * ... + * ... + * + * + * @scope + * @priority 800 + * @param {*} ngSwitch|on expression to match against ng-switch-when. + * @paramDescription + * On child elements add: + * + * * `ngSwitchWhen`: the case statement to match against. If match then this + * case will be displayed. If the same match appears multiple times, all the + * elements will be displayed. + * * `ngSwitchDefault`: the default case when no other case match. If there + * are multiple default cases, all of them will be displayed when no other + * case match. + * + * + * @example + + +
+ + selection={{selection}} +
+
+
Settings Div
+
Home Span
+
default
+
+
+
+ + function Ctrl($scope) { + $scope.items = ['settings', 'home', 'other']; + $scope.selection = $scope.items[0]; + } + + + .animate-switch-container { + position:relative; + background:white; + border:1px solid black; + height:40px; + overflow:hidden; + } + + .animate-switch { + padding:10px; + } + + .animate-switch.ng-animate { + -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; + transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; + + position:absolute; + top:0; + left:0; + right:0; + bottom:0; + } + + .animate-switch.ng-leave.ng-leave-active, + .animate-switch.ng-enter { + top:-50px; + } + .animate-switch.ng-leave, + .animate-switch.ng-enter.ng-enter-active { + top:0; + } + + + it('should start in settings', function() { + expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/); + }); + it('should change to home', function() { + select('selection').option('home'); + expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/); + }); + it('should select default', function() { + select('selection').option('other'); + expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/); + }); + +
+ */ +var ngSwitchDirective = ['$animate', function($animate) { + return { + restrict: 'EA', + require: 'ngSwitch', + + // asks for $scope to fool the BC controller module + controller: ['$scope', function ngSwitchController() { + this.cases = {}; + }], + link: function(scope, element, attr, ngSwitchController) { + var watchExpr = attr.ngSwitch || attr.on, + selectedTranscludes, + selectedElements, + selectedScopes = []; + + scope.$watch(watchExpr, function ngSwitchWatchAction(value) { + for (var i= 0, ii=selectedScopes.length; i + + +
+
+
+ {{text}} +
+
+ + it('should have transcluded', function() { + input('title').enter('TITLE'); + input('text').enter('TEXT'); + expect(binding('title')).toEqual('TITLE'); + expect(binding('text')).toEqual('TEXT'); + }); + + + * + */ +var ngTranscludeDirective = ngDirective({ + controller: ['$element', '$transclude', function($element, $transclude) { + if (!$transclude) { + throw minErr('ngTransclude')('orphan', + 'Illegal use of ngTransclude directive in the template! ' + + 'No parent directive that requires a transclusion found. ' + + 'Element: {0}', + startingTag($element)); + } + + // remember the transclusion fn but call it during linking so that we don't process transclusion before directives on + // the parent element even when the transclusion replaces the current element. (we can't use priority here because + // that applies only to compile fns and not controllers + this.$transclude = $transclude; + }], + + link: function($scope, $element, $attrs, controller) { + controller.$transclude(function(clone) { + $element.html(''); + $element.append(clone); + }); + } +}); + +/** + * @ngdoc directive + * @name ng.directive:script + * @restrict E + * + * @description + * Load content of a script tag, with type `text/ng-template`, into `$templateCache`, so that the + * template can be used by `ngInclude`, `ngView` or directive templates. + * + * @param {'text/ng-template'} type must be set to `'text/ng-template'` + * + * @example + + + + + Load inlined template +
+
+ + it('should load template defined inside script tag', function() { + element('#tpl-link').click(); + expect(element('#tpl-content').text()).toMatch(/Content of the template/); + }); + +
+ */ +var scriptDirective = ['$templateCache', function($templateCache) { + return { + restrict: 'E', + terminal: true, + compile: function(element, attr) { + if (attr.type == 'text/ng-template') { + var templateUrl = attr.id, + // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent + text = element[0].text; + + $templateCache.put(templateUrl, text); + } + } + }; +}]; + +var ngOptionsMinErr = minErr('ngOptions'); +/** + * @ngdoc directive + * @name ng.directive:select + * @restrict E + * + * @description + * HTML `SELECT` element with angular data-binding. + * + * # `ngOptions` + * + * The `ngOptions` attribute can be used to dynamically generate a list of `` + * DOM element. + * * `trackexpr`: Used when working with an array of objects. The result of this expression will be + * used to identify the objects in the array. The `trackexpr` will most likely refer to the + * `value` variable (e.g. `value.propertyName`). + * + * @example + + + +
+
    +
  • + Name: + [X] +
  • +
  • + [add] +
  • +
+
+ Color (null not allowed): +
+ + Color (null allowed): + + +
+ + Color grouped by shade: +
+ + + Select bogus.
+
+ Currently selected: {{ {selected_color:color} }} +
+
+
+
+ + it('should check ng-options', function() { + expect(binding('{selected_color:color}')).toMatch('red'); + select('color').option('0'); + expect(binding('{selected_color:color}')).toMatch('black'); + using('.nullable').select('color').option(''); + expect(binding('{selected_color:color}')).toMatch('null'); + }); + +
+ */ + +var ngOptionsDirective = valueFn({ terminal: true }); +// jshint maxlen: false +var selectDirective = ['$compile', '$parse', function($compile, $parse) { + //0000111110000000000022220000000000000000000000333300000000000000444444444444444000000000555555555555555000000066666666666666600000000000000007777000000000000000000088888 + var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/, + nullModelCtrl = {$setViewValue: noop}; +// jshint maxlen: 100 + + return { + restrict: 'E', + require: ['select', '?ngModel'], + controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) { + var self = this, + optionsMap = {}, + ngModelCtrl = nullModelCtrl, + nullOption, + unknownOption; + + + self.databound = $attrs.ngModel; + + + self.init = function(ngModelCtrl_, nullOption_, unknownOption_) { + ngModelCtrl = ngModelCtrl_; + nullOption = nullOption_; + unknownOption = unknownOption_; + }; + + + self.addOption = function(value) { + assertNotHasOwnProperty(value, '"option value"'); + optionsMap[value] = true; + + if (ngModelCtrl.$viewValue == value) { + $element.val(value); + if (unknownOption.parent()) unknownOption.remove(); + } + }; + + + self.removeOption = function(value) { + if (this.hasOption(value)) { + delete optionsMap[value]; + if (ngModelCtrl.$viewValue == value) { + this.renderUnknownOption(value); + } + } + }; + + + self.renderUnknownOption = function(val) { + var unknownVal = '? ' + hashKey(val) + ' ?'; + unknownOption.val(unknownVal); + $element.prepend(unknownOption); + $element.val(unknownVal); + unknownOption.prop('selected', true); // needed for IE + }; + + + self.hasOption = function(value) { + return optionsMap.hasOwnProperty(value); + }; + + $scope.$on('$destroy', function() { + // disable unknown option so that we don't do work when the whole select is being destroyed + self.renderUnknownOption = noop; + }); + }], + + link: function(scope, element, attr, ctrls) { + // if ngModel is not defined, we don't need to do anything + if (!ctrls[1]) return; + + var selectCtrl = ctrls[0], + ngModelCtrl = ctrls[1], + multiple = attr.multiple, + optionsExp = attr.ngOptions, + nullOption = false, // if false, user will not be able to select it (used by ngOptions) + emptyOption, + // we can't just jqLite('",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
t
",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t +}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); +u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("'; +html += '
'; +html += '
from table fragments + if ( !jQuery.support.tbody ) { + + // String was a
'; +html += '
Upload File
'; +html += '
Want to upload multiple files at once? Please upgrade to the latest Flash Player, then reload this page. For some reason our Flash based uploader did not load, so you are currently using our single file uploader.
'; +html += spacer(1,20) + '
'; +var url = zero_client.targetURL; +if (url.indexOf('?') > -1) url += '&'; else url += '?'; +url += 'format=jshtml&onafter=' + escape('window.parent.upload_basic_finish(response);'); +Debug.trace('upload', "Prepping basic upload: " + url); +html += '
'; +html += '
'; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "hide_popup_dialog()") + ' ' + large_icon_button('page_white_get.png', 'Upload', "upload_basic_go()") + '
'; +html += '
'; +html += ''; +html += '
'; +html += ''; +session.hooks.keys[ESC_KEY] = 'hide_popup_dialog'; +show_popup_dialog(528, 200, html); +} +function upload_basic_go() { +$('f_upload_basic').submit(); +$('d_upload_form').hide(); +$('d_upload_progress').show(); +} +function upload_basic_finish(response) { +Debug.trace('upload', "Basic upload complete: " + dumper(response)); +setTimeout( 'upload_basic_finish_2()', 100 ); +} +function upload_basic_finish_2() { +$('i_upload_basic').src = 'blank.html'; +setTimeout( 'upload_basic_finish_3()', 100 ); +} +function upload_basic_finish_3() { +hide_popup_dialog(); +delete session.progress; +show_progress_dialog( 0, 'Finishing Upload...', true ); +fire_callback( session.upload_callback ); +} +function upload_destroy() { +if (zero_client) { +zero_client.destroy(); +delete ZeroUpload.clients[ zero_client.id ]; +zero_client = null; +} +} +function prep_upload(dom_id, url, callback, types) { +session.upload_callback = callback; +if (url) { +if (url.indexOf('?') > -1) url += '&'; else url += '?'; +url += 'session=' + session.cookie.get('effect_session_id'); +} +upload_destroy(); +zero_client = new ZeroUpload.Client(); +if (url) zero_client.setURL( url ); +zero_client.setHandCursor( true ); +if (types) zero_client.setFileTypes( types[0], types[1] ); +zero_client.addEventListener( 'queueStart', uploadQueueStart ); +zero_client.addEventListener( 'fileStart', uploadFileStart ); +zero_client.addEventListener( 'progress', uploadProgress ); +zero_client.addEventListener( 'fileComplete', uploadFileComplete ); +zero_client.addEventListener( 'queueComplete', uploadQueueComplete ); +zero_client.addEventListener( 'error', uploadError ); +zero_client.addEventListener( 'debug', function(client, eventName, args) { +Debug.trace('upload', "Caught event: " + eventName); +} ); +if (dom_id) { +Debug.trace('upload', "Gluing ZeroUpload to: " + dom_id); +zero_client.glue( dom_id ); +} +} +Class.create( 'Debug', { +__static: { +enabled: false, +categories: { all: 1 }, +buffer: [], +max_rows: 5000, +win: null, +ie: !!navigator.userAgent.match(/MSIE/), +ie6: !!navigator.userAgent.match(/MSIE\D+6/), +init: function() { +Debug.enabled = true; +Debug.trace( 'debug', 'Debug log start' ); +var html = '

'; +if (Debug.ie) { +setTimeout( function() { +document.body.insertAdjacentHTML('beforeEnd', +'
' + html + '
' +); +}, 1000 ); +} +else { +var div = document.createElement('DIV'); +div.id = 'd_debug'; +div.setAttribute('id', 'd_debug'); +div.style.position = Debug.ie6 ? 'absolute' : 'fixed'; +div.style.zIndex = '101'; +div.style.left = '0px'; +div.style.top = '0px'; +div.style.width = '100%'; +div.innerHTML = html; +document.getElementsByTagName('body')[0].appendChild(div); +} +}, +show: function() { +if (!Debug.win || Debug.win.closed) { +Debug.trace('debug', "Opening debug window"); +Debug.win = window.open( '', 'DebugWindow', 'width=600,height=500,menubar=no,resizable=yes,scrollbars=yes,location=no,status=no,toolbar=no,directories=no' ); +if (!Debug.win) return alert("Failed to open window. Popup blocker maybe?"); +var doc = Debug.win.document; +doc.open(); +doc.writeln( 'Debug Log' ); +doc.writeln( '
' ); +doc.writeln( '
' ); +doc.writeln( '
' ); +doc.writeln( '' ); +doc.writeln( '' ); +doc.writeln( '
' ); +doc.writeln( '' ); +doc.close(); +} +Debug.win.focus(); +}, +console_execute: function() { +var cmd = Debug.win.document.getElementById('fe_command'); +if (cmd.value.length) { +Debug.trace( 'console', cmd.value ); +try { +Debug.trace( 'console', '' + eval(cmd.value) ); +} +catch (e) { +Debug.trace( 'error', 'JavaScript Interpreter Exception: ' + e.toString() ); +} +} +}, +get_time_stamp: function(now) { +var date = new Date( now * 1000 ); +var hh = date.getHours(); if (hh < 10) hh = "0" + hh; +var mi = date.getMinutes(); if (mi < 10) mi = "0" + mi; +var ss = date.getSeconds(); if (ss < 10) ss = "0" + ss; +var sss = '' + date.getMilliseconds(); while (sss.length < 3) sss = "0" + sss; +return '' + hh + ':' + mi + ':' + ss + '.' + sss; +}, +refresh_console: function() { +if (!Debug.win || Debug.win.closed) return; +var div = Debug.win.document.getElementById('d_debug_log'); +if (div) { +var row = null; +while ( row = Debug.buffer.shift() ) { +var time_stamp = Debug.get_time_stamp(row.time); +var msg = row.msg; +msg = msg.replace(/\t/g, "    "); +msg = msg.replace(//g, ">"); +msg = msg.replace(/\n/g, "
\n"); +var html = ''; +var sty = 'float:left; font-family: Consolas, Courier, mono; font-size: 12px; cursor:default; margin-right:10px; margin-bottom:1px; padding:2px;'; +html += '
' + time_stamp + '
'; +html += '
' + row.cat + '
'; +html += '
' + msg + '
'; +html += '
'; +var chunk = Debug.win.document.createElement('DIV'); +chunk.style['float'] = 'none'; +chunk.innerHTML = html; +div.appendChild(chunk); +} +var cmd = Debug.win.document.getElementById('fe_command'); +cmd.focus(); +} +Debug.dirty = 0; +Debug.win.scrollTo(0, 99999); +}, +hires_time_now: function() { +var now = new Date(); +return ( now.getTime() / 1000 ); +}, +trace: function(cat, msg) { +if (arguments.length == 1) { +msg = cat; +cat = 'debug'; +} +if (Debug.categories.all || Debug.categories[cat]) { +Debug.buffer.push({ cat: cat, msg: msg, time: Debug.hires_time_now() }); +if (Debug.buffer.length > Debug.max_rows) Debug.buffer.shift(); +if (!Debug.dirty) { +Debug.dirty = 1; +setTimeout( 'Debug.refresh_console();', 1 ); +} +} +} +} +} ); +var session = { +inited: false, +api_mod_cache: {}, +query: parseQueryString( ''+location.search ), +cookie: new CookieTree({ path: '/effect/' }), +storage: {}, +storage_dirty: false, +hooks: { +keys: {} +}, +username: '', +em_width: 11, +audioResourceMatch: /\.mp3$/i, +imageResourceMatch: /\.(jpe|jpeg|jpg|png|gif)$/i, +textResourceMatch: /\.xml$/i, +movieResourceMatch: /\.(flv|mp4|mp4v|mov|3gp|3g2)$/i, +imageResourceMatchString: '\.(jpe|jpeg|jpg|png|gif)$' +}; +session.debug = session.query.debug ? true : false; +var page_manager = null; +var preload_icons = []; +var preload_images = [ +'loading.gif', +'aquaprogressbar.gif', +'aquaprogressbar_bkgnd.gif' +]; +function get_base_url() { +return protocol + '://' + location.hostname + session.config.BaseURI; +} +function effect_init() { +if (session.inited) return; +session.inited = true; +assert( window.config, "Config not loaded" ); +session.config = window.config; +Debug.trace("Starting up"); +rendering_page = false; +preload(); +window.$R = {}; +for (var key in config.RegExpShortcuts) { +$R[key] = new RegExp( config.RegExpShortcuts[key] ); +} +ww_precalc_font("body", "effect_precalc_font_finish"); +page_manager = new Effect.PageManager( config.Pages.Page ); +var session_id = session.cookie.get('effect_session_id'); +if (session_id && session_id.match(/^login/)) { +do_session_recover(); +} +else { +show_default_login_status(); +Nav.init(); +} +Blog.search({ +stag: 'sidebar_docs', +limit: 20, +title_only: true, +sort_by: 'seq', +sort_dir: -1, +target: 'd_sidebar_documents', +outer_div_class: 'sidebar_blog_row', +title_class: 'sidebar_blog_title', +after: '' +}); +Blog.search({ +stag: 'sidebar_tutorials', +limit: 5, +title_only: true, +sort_by: 'seq', +sort_dir: -1, +target: 'd_sidebar_tutorials', +outer_div_class: 'sidebar_blog_row', +title_class: 'sidebar_blog_title', +after: '' +}); +Blog.search({ +stag: 'sidebar_plugins', +limit: 5, +title_only: true, +sort_by: 'seq', +sort_dir: -1, +target: 'd_sidebar_plugins', +outer_div_class: 'sidebar_blog_row', +title_class: 'sidebar_blog_title', +after: '' +}); +$('fe_search_bar').onkeydown = delay_onChange_input_text; +user_storage_idle(); +} +function effect_precalc_font_finish(width, height) { +session.em_width = width; +} +function preload() { +for (var idx = 0, len = preload_icons.length; idx < len; idx++) { +var url = images_uri + '/icons/' + preload_icons[idx] + '.gif'; +preload_icons[idx] = new Image(); +preload_icons[idx].src = url; +} +for (var idx = 0, len = preload_images.length; idx < len; idx++) { +var url = images_uri + '/' + preload_images[idx]; +preload_images[idx] = new Image(); +preload_images[idx].src = url; +} +} +function $P(id) { +if (!id) id = page_manager.current_page_id; +var page = page_manager.find(id); +assert( !!page, "Failed to locate page: " + id ); +return page; +} +function get_pref(name) { +if (!session.user || !session.user.Preferences) return alert("ASSERT FAILURE! Tried to lookup pref " + name + " and user is not yet loaded!"); +return session.user.Preferences[name]; +} +function get_bool_pref(name) { +return (get_pref(name) == 1); +} +function set_pref(name, value) { +session.user.Preferences[name] = value; +} +function set_bool_pref(name, value) { +set_pref(name, value ? '1' : '0'); +} +function save_prefs() { +var prefs_to_save = {}; +if (arguments.length) { +for (var idx = 0, len = arguments.length; idx < len; idx++) { +var key = arguments[idx]; +prefs_to_save[key] = get_pref(key); +} +} +else prefs_to_save = session.user.Preferences; +effect_api_mod_touch('user_get'); +effect_api_send('user_update', { +Username: session.username, +Preferences: prefs_to_save +}, 'save_prefs_2'); +} +function save_prefs_2(response) { +do_message('success', 'Preferences saved.'); +} + +function get_full_name(username) { +var user = session.users[username]; +if (!user) return username; +return user.FullName; +} +function get_buddy_icon_url(username, size) { +var mod = session.api_mod_cache.get_buddy_icon || 0; +if (!size) size = 32; +var url = '/effect/api/get_buddy_icon?username='+username + '&mod=' + mod + '&size=' + size; +return url; +} +function get_buddy_icon_display(username, show_icon, show_name) { +if ((typeof(show_icon) == 'undefined') && get_bool_pref('show_user_icons')) show_icon = 1; +if ((typeof(show_name) == 'undefined') && get_bool_pref('show_user_names')) show_name = 1; +var html = ''; +if (show_icon) html += ''; +if (show_icon && show_name) html += '
'; +if (show_name) html += username; +return html; +} +function do_session_recover() { +session.hooks.after_error = 'do_logout'; +effect_api_send('session_recover', {}, 'do_login_2', { _from_recover: 1 } ); +} +function require_login() { +if (session.user) return true; +Debug.trace('Page requires login, showing login page'); +session.nav_after_login = Nav.currentAnchor(); +setTimeout( function() { +Nav.go( 'Login' ); +}, 1 ); +return false; +} +function popup_window(url, name) { +if (!url) url = ''; +if (!name) name = ''; +var win = window.open(url, name); +if (!win) return alert('Failed to open popup window. If you have a popup blocker, please disable it for this website and try again.'); +return win; +} +function do_login_prompt() { +hide_popup_dialog(); +delete session.progress; +if (!session.temp_password) session.temp_password = ''; +if (!session.username) session.username = ''; +var temp_username = session.open_id || session.username || ''; +var html = ''; +html += '
'; +html += '\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "
'; +html += '
Effect Developer Login
'; +html += '
'; +html += '
Effect Username  or  '+icon('openid', 'OpenID', 'popup_window(\'http://openid.net/\')', 'What is OpenID?')+'


'; +html += '
'; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "clear_login()") + ' ' + large_icon_button('check', 'Login', 'do_login()') + '
'; +html += '
'; +html += ''; +session.hooks.keys[ENTER_KEY] = 'do_login'; +session.hooks.keys[ESC_KEY] = 'clear_login'; +safe_focus( 'fe_username' ); +show_popup_dialog(450, 225, html); +} +function do_openid_reg(title, auto_login_button) { +hide_popup_dialog(); +delete session.progress; +if (!title) title = 'Register Account Using OpenID'; +if (typeof(auto_login_button) == 'undefined') auto_login_button = 1; +var html = ''; +html += '
'; +html += '
'; +html += '
'+title+'
'; +html += '
'; +html += '
'+icon('openid', 'Enter Your OpenID URL:')+'
'; +if (auto_login_button) html += '


'; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "hide_popup_dialog()") + ' ' + large_icon_button('check', title.match(/login/i) ? 'Login' : 'Register', 'do_openid_login()') + '
'; +html += '
'; +html += ''; +session.hooks.keys[ENTER_KEY] = 'do_openid_login'; +session.hooks.keys[ESC_KEY] = 'hide_popup_dialog'; +safe_focus( 'fe_username' ); +show_popup_dialog(450, 225, html); +} +function do_login_prompt_2() { +hide_popup_dialog(); +delete session.progress; +if (!session.temp_password) session.temp_password = ''; +if (!session.username) session.username = ''; +var html = ''; +html += '
'; +html += '"; + second_cell = ""; + row = $("").attr("id", "s" + index).attr("class", "location_row").html(first_cell + second_cell); + $locationsDiv.append(row); + } + if (index === this.numSearchToDisplay) { + $locationsDiv.append(""); + return $locationsDiv.append(""); + } + }, this); + return this.geocoder.geocode({ + address: address + }, __bind(function(result, status) { + if (status !== "OK") { + $('.error_message').html(t("Search Address Failed")).fadeIn(); + return; + } + _.each(result, showResults); + $("#search_results").html($locationsDiv); + this.locationChange("search"); + this.searchResults = result; + return this.displaySearchLoc(); + }, this)); + }; + ClientsRequestView.prototype.mouseoverLocation = function(e) { + var $el, id, marker; + $el = $(e.currentTarget); + id = $el.attr("id").substring(1); + marker = this.markers[id]; + return marker.setAnimation(google.maps.Animation.BOUNCE); + }; + ClientsRequestView.prototype.mouseoutLocation = function(e) { + var $el, id, marker; + $el = $(e.currentTarget); + id = $el.attr("id").substring(1); + marker = this.markers[id]; + return marker.setAnimation(null); + }; + ClientsRequestView.prototype.searchLocation = function(e) { + e.preventDefault(); + $("#address").val($(e.currentTarget).html()); + return this.searchAddress(); + }; + ClientsRequestView.prototype.favoriteClick = function(e) { + var index, location; + e.preventDefault(); + $(".favorites").attr("href", ""); + index = $(e.currentTarget).removeAttr("href").attr("id"); + location = new google.maps.LatLng(USER.locations[index].latitude, USER.locations[index].longitude); + return this.panToLocation(location); + }; + ClientsRequestView.prototype.clickLocation = function(e) { + var id; + id = $(e.currentTarget).attr("id").substring(1); + return this.panToLocation(this.markers[id].getPosition()); + }; + ClientsRequestView.prototype.panToLocation = function(location) { + this.map.panTo(location); + this.map.setZoom(16); + return this.pickup_icon.setPosition(location); + }; + ClientsRequestView.prototype.locationLinkHandle = function(e) { + var panelName; + e.preventDefault(); + panelName = $(e.currentTarget).attr("id"); + return this.locationChange(panelName); + }; + ClientsRequestView.prototype.locationChange = function(type) { + $(".locations_link").attr("href", "").css("font-weight", "normal"); + switch (type) { + case "favorite": + $(".search_results").attr("href", ""); + $(".locations_link#favorite").removeAttr("href").css("font-weight", "bold"); + $("#search_results").hide(); + $("#favorite_results").fadeIn(); + return this.displayFavLoc(); + case "search": + $(".favorites").attr("href", ""); + $(".locations_link#search").removeAttr("href").css("font-weight", "bold"); + $("#favorite_results").hide(); + $("#search_results").fadeIn(); + return this.displaySearchLoc(); + } + }; + ClientsRequestView.prototype.rateTrip = function(e) { + var rating; + rating = $(e.currentTarget).attr("id"); + $(".stars").attr("src", "/web/img/star_inactive.png"); + return _(rating).times(function(index) { + return $(".stars#" + (index + 1)).attr("src", "/web/img/star_active.png"); + }); + }; + ClientsRequestView.prototype.pickupHandle = function(e) { + var $el, callback, message; + e.preventDefault(); + $el = $(e.currentTarget).find("span"); + switch ($el.html()) { + case t("Request Pickup"): + _.delay(this.requestRide, 3000); + $("#status_message").html(t("Sending pickup request...")); + $el.html(t("Cancel Pickup")).parent().attr("class", "button_red"); + this.pickup_icon.setDraggable(false); + this.map.panTo(this.pickup_icon.getPosition()); + return this.map.setZoom(18); + case t("Cancel Pickup"): + if (this.status === "ready") { + $el.html(t("Request Pickup")).parent().attr("class", "button_green"); + return this.pickup_icon.setDraggable(true); + } else { + callback = __bind(function(v, m, f) { + if (v) { + this.AskDispatch("PickupCanceledClient"); + return this.setStatus("ready"); + } + }, this); + message = t("Cancel Request Prompt"); + if (this.status === "arriving") { + message = 'Cancel Request Arrived Prompt'; + } + return $.prompt(message, { + buttons: { + Ok: true, + Cancel: false + }, + callback: callback + }); + } + } + }; + ClientsRequestView.prototype.requestRide = function() { + if ($("#pickupHandle").find("span").html() === t("Cancel Pickup")) { + this.AskDispatch("Pickup"); + return this.setStatus("searching"); + } + }; + ClientsRequestView.prototype.removeCabs = function() { + _.each(this.cabs, __bind(function(point) { + return point.setMap(null); + }, this)); + return this.cabs = []; + }; + ClientsRequestView.prototype.addToFavLoc = function(e) { + var $el, lat, lng, nickname; + e.preventDefault(); + $el = $(e.currentTarget); + $el.find(".error_message").html(""); + nickname = $el.find("#favLocNickname").val().toString(); + lat = $el.find("#pickupLat").val().toString(); + lng = $el.find("#pickupLng").val().toString(); + if (nickname.length < 3) { + $el.find(".error_message").html(t("Favorite Location Nickname Length Error")); + return; + } + this.ShowSpinner("submit"); + return $.ajax({ + type: 'POST', + url: API + "/locations", + dataType: 'json', + data: { + token: USER.token, + nickname: nickname, + latitude: lat, + longitude: lng + }, + success: __bind(function(data, textStatus, jqXHR) { + return $el.html(t("Favorite Location Save Succeeded")); + }, this), + error: __bind(function(jqXHR, textStatus, errorThrown) { + return $el.find(".error_message").html(t("Favorite Location Save Failed")); + }, this), + complete: __bind(function(data) { + return this.HideSpinner(); + }, this) + }); + }; + ClientsRequestView.prototype.showFavLoc = function(e) { + $(e.currentTarget).fadeOut(); + return $("#favLoc_form").fadeIn(); + }; + ClientsRequestView.prototype.selectInputText = function(e) { + e.currentTarget.focus(); + return e.currentTarget.select(); + }; + ClientsRequestView.prototype.displayFavLoc = function() { + var alphabet, bounds; + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + this.removeMarkers(); + bounds = new google.maps.LatLngBounds(); + _.each(USER.locations, __bind(function(location, index) { + var marker; + marker = new google.maps.Marker({ + position: new google.maps.LatLng(location.latitude, location.longitude), + map: this.map, + title: t("Favorite Location Title", { + id: alphabet != null ? alphabet[index] : void 0 + }), + icon: "https://www.google.com/mapfiles/marker" + alphabet[index] + ".png" + }); + this.markers.push(marker); + bounds.extend(marker.getPosition()); + return google.maps.event.addListener(marker, 'click', __bind(function() { + return this.pickup_icon.setPosition(marker.getPosition()); + }, this)); + }, this)); + this.pickup_icon.setPosition(_.first(this.markers).getPosition()); + return this.map.fitBounds(bounds); + }; + ClientsRequestView.prototype.displaySearchLoc = function() { + var alphabet; + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + this.removeMarkers(); + return _.each(this.searchResults, __bind(function(result, index) { + var marker; + if (index < this.numSearchToDisplay) { + marker = new google.maps.Marker({ + position: result.geometry.location, + map: this.map, + title: t("Search Location Title", { + id: alphabet != null ? alphabet[index] : void 0 + }), + icon: "https://www.google.com/mapfiles/marker" + alphabet[index] + ".png" + }); + this.markers.push(marker); + return this.panToLocation(result.geometry.location); + } + }, this)); + }; + ClientsRequestView.prototype.removeMarkers = function() { + _.each(this.markers, __bind(function(marker) { + return marker.setMap(null); + }, this)); + return this.markers = []; + }; + ClientsRequestView.prototype.AskDispatch = function(ask, options) { + var attrs, lowestETA, processData, showCab; + if (ask == null) { + ask = ""; + } + if (options == null) { + options = {}; + } + switch (ask) { + case "NearestCab": + attrs = { + latitude: this.pickup_icon.getPosition().lat(), + longitude: this.pickup_icon.getPosition().lng() + }; + lowestETA = 99999; + showCab = __bind(function(cab) { + var point; + point = new google.maps.Marker({ + position: new google.maps.LatLng(cab.latitude, cab.longitude), + map: this.map, + icon: this.cabMarker, + title: t("ETA Message", { + minutes: app.helpers.FormatSeconds(cab != null ? cab.eta : void 0, true) + }) + }); + if (cab.eta < lowestETA) { + lowestETA = cab.eta; + } + return this.cabs.push(point); + }, this); + processData = __bind(function(data, textStatus, jqXHR) { + if (this.status === "ready") { + this.removeCabs(); + if (data.sorry) { + $("#status_message").html(data.sorry).fadeIn(); + } else { + _.each(data.driverLocations, showCab); + $("#status_message").html(t("Nearest Cab Message", { + minutes: app.helpers.FormatSeconds(lowestETA, true) + })).fadeIn(); + } + if (Backbone.history.fragment === "!/request") { + return _.delay(this.showCabs, this.pollInterval); + } + } + }, this); + return this.AjaxCall(ask, processData, attrs); + case "StatusClient": + processData = __bind(function(data, textStatus, jqXHR) { + var bounds, cabLocation, locationSaved, point, userLocation; + if (data.messageType === "OK") { + switch (data.status) { + case "completed": + this.removeCabs(); + this.setStatus("rate"); + return this.fetchTripDetails(data.tripID); + case "open": + return this.setStatus("ready"); + case "begintrip": + this.setStatus("riding"); + cabLocation = new google.maps.LatLng(data.latitude, data.longitude); + this.removeCabs(); + this.pickup_icon.setMap(null); + point = new google.maps.Marker({ + position: cabLocation, + map: this.map, + icon: this.cabMarker + }); + this.cabs.push(point); + this.map.panTo(point.getPosition()); + $("#rideName").html(data.driverName); + $("#ridePhone").html(data.driverMobile); + $("#ride_address_wrapper").hide(); + if (Backbone.history.fragment === "!/request") { + return _.delay(this.AskDispatch, this.pollInterval, "StatusClient"); + } + break; + case "pending": + this.setStatus("searching"); + if (Backbone.history.fragment === "!/request") { + return _.delay(this.AskDispatch, this.pollInterval, "StatusClient"); + } + break; + case "accepted": + case "arrived": + if (data.status === "accepted") { + this.setStatus("waiting"); + $("#status_message").html(t("Arrival ETA Message", { + minutes: app.helpers.FormatSeconds(data.eta, true) + })); + } else { + this.setStatus("arriving"); + $("#status_message").html(t("Arriving Now Message")); + } + userLocation = new google.maps.LatLng(data.pickupLocation.latitude, data.pickupLocation.longitude); + cabLocation = new google.maps.LatLng(data.latitude, data.longitude); + this.pickup_icon.setPosition(userLocation); + this.removeCabs(); + $("#rideName").html(data.driverName); + $("#ridePhone").html(data.driverMobile); + if ($("#rideAddress").html() === "") { + locationSaved = false; + _.each(USER.locations, __bind(function(location) { + if (parseFloat(location.latitude) === parseFloat(data.pickupLocation.latitude) && parseFloat(location.longitude) === parseFloat(data.pickupLocation.longitude)) { + return locationSaved = true; + } + }, this)); + if (locationSaved) { + $("#addToFavButton").hide(); + } + $("#pickupLat").val(data.pickupLocation.latitude); + $("#pickupLng").val(data.pickupLocation.longitude); + this.geocoder.geocode({ + location: userLocation + }, __bind(function(result, status) { + $("#rideAddress").html(result[0].formatted_address); + return $("#favLocNickname").val("" + result[0].address_components[0].short_name + " " + result[0].address_components[1].short_name); + }, this)); + } + point = new google.maps.Marker({ + position: cabLocation, + map: this.map, + icon: this.cabMarker + }); + this.cabs.push(point); + bounds = bounds = new google.maps.LatLngBounds(); + bounds.extend(cabLocation); + bounds.extend(userLocation); + this.map.fitBounds(bounds); + if (Backbone.history.fragment === "!/request") { + return _.delay(this.AskDispatch, this.pollInterval, "StatusClient"); + } + } + } + }, this); + return this.AjaxCall(ask, processData); + case "Pickup": + attrs = { + latitude: this.pickup_icon.getPosition().lat(), + longitude: this.pickup_icon.getPosition().lng() + }; + processData = __bind(function(data, textStatus, jqXHR) { + if (data.messageType === "Error") { + return $("#status_message").html(data.description); + } else { + return this.AskDispatch("StatusClient"); + } + }, this); + return this.AjaxCall(ask, processData, attrs); + case "PickupCanceledClient": + processData = __bind(function(data, textStatus, jqXHR) { + if (data.messageType === "OK") { + return this.setStatus("ready"); + } else { + return $("#status_message").html(data.description); + } + }, this); + return this.AjaxCall(ask, processData, attrs); + case "RatingDriver": + attrs = { + rating: options.rating + }; + processData = __bind(function(data, textStatus, jqXHR) { + if (data.messageType === "OK") { + this.setStatus("init"); + } else { + $("status_message").html(t("Rating Driver Failed")); + } + return this.HideSpinner(); + }, this); + return this.AjaxCall(ask, processData, attrs); + case "Feedback": + attrs = { + message: options.message + }; + processData = __bind(function(data, textStatus, jqXHR) { + if (data.messageType === "OK") { + return alert("rated"); + } + }, this); + return this.AjaxCall(ask, processData, attrs); + } + }; + ClientsRequestView.prototype.AjaxCall = function(type, successCallback, attrs) { + if (attrs == null) { + attrs = {}; + } + _.extend(attrs, { + token: USER.token, + messageType: type, + app: "client", + version: "1.0.60", + device: "web" + }); + return $.ajax({ + type: 'POST', + url: DISPATCH + "/", + processData: false, + data: JSON.stringify(attrs), + success: successCallback, + dataType: 'json', + error: __bind(function(jqXHR, textStatus, errorThrown) { + $("#status_message").html(errorThrown); + return this.HideSpinner(); + }, this) + }); + }; + return ClientsRequestView; + })(); +}).call(this); +}, "views/clients/settings": function(exports, require, module) {(function() { + var clientsSettingsTemplate; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsSettingsTemplate = require('templates/clients/settings'); + exports.ClientsSettingsView = (function() { + __extends(ClientsSettingsView, UberView); + function ClientsSettingsView() { + this.render = __bind(this.render, this); + this.initialize = __bind(this.initialize, this); + ClientsSettingsView.__super__.constructor.apply(this, arguments); + } + ClientsSettingsView.prototype.id = 'settings_view'; + ClientsSettingsView.prototype.className = 'view_container'; + ClientsSettingsView.prototype.events = { + 'submit #profile_pic_form': 'processPicUpload', + 'click #submit_pic': 'processPicUpload', + 'click a.setting_change': "changeTab", + 'submit #edit_info_form': "submitInfo", + 'click #change_password': 'changePass' + }; + ClientsSettingsView.prototype.divs = { + 'info_div': "Information", + 'pic_div': "Picture" + }; + ClientsSettingsView.prototype.pageTitle = t("Settings") + " | " + t("Uber"); + ClientsSettingsView.prototype.tabTitle = { + 'info_div': t("Information"), + 'pic_div': t("Picture") + }; + ClientsSettingsView.prototype.initialize = function() { + return this.mixin(require('web-lib/mixins/i18n_phone_form').i18nPhoneForm); + }; + ClientsSettingsView.prototype.render = function(type) { + if (type == null) { + type = "info"; + } + this.RefreshUserInfo(__bind(function() { + var $el, alphabet; + this.delegateEvents(); + this.HideSpinner(); + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + $el = $(this.el); + $(this.el).html(clientsSettingsTemplate({ + type: type + })); + $el.find("#" + type + "_div").show(); + $el.find("a[href='" + type + "_div']").parent().addClass("active"); + return document.title = "" + this.tabTitle[type + '_div'] + " " + this.pageTitle; + }, this)); + this.delegateEvents(); + return this; + }; + ClientsSettingsView.prototype.changeTab = function(e) { + var $eTarget, $el, div, link, pageDiv, _i, _j, _len, _len2, _ref, _ref2; + e.preventDefault(); + $eTarget = $(e.currentTarget); + this.ClearGlobalStatus(); + $el = $(this.el); + _ref = $el.find(".setting_change"); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + link = _ref[_i]; + $(link).parent().removeClass("active"); + } + $eTarget.parent().addClass("active"); + _ref2 = _.keys(this.divs); + for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { + div = _ref2[_j]; + $el.find("#" + div).hide(); + } + pageDiv = $eTarget.attr('href'); + $el.find("#" + pageDiv).show(); + Backbone.history.navigate("!/settings/" + (this.divs[pageDiv].toLowerCase().replace(" ", "-")), false); + document.title = "" + this.tabTitle[pageDiv] + " " + this.pageTitle; + if (pageDiv === "loc_div") { + try { + google.maps.event.trigger(this.map, 'resize'); + return this.map.fitBounds(this.bounds); + } catch (_e) {} + } + }; + ClientsSettingsView.prototype.submitInfo = function(e) { + var $e, attrs, client, options; + $('#global_status').find('.success_message').text(''); + $('#global_status').find('.error_message').text(''); + $('.error_message').text(''); + e.preventDefault(); + $e = $(e.currentTarget); + attrs = $e.serializeToJson(); + attrs['mobile_country_id'] = this.$('#mobile_country_id').val(); + if (attrs['password'] === '') { + delete attrs['password']; + } + options = { + success: __bind(function(response) { + this.ShowSuccess(t("Information Update Succeeded")); + return this.RefreshUserInfo(); + }, this), + error: __bind(function(model, data) { + var errors; + if (data.status === 406) { + errors = JSON.parse(data.responseText); + return _.each(_.keys(errors), function(field) { + return $("#" + field).parent().find('span.error_message').text(errors[field]); + }); + } else { + return this.ShowError(t("Information Update Failed")); + } + }, this), + type: "PUT" + }; + client = new app.models.client({ + id: USER.id + }); + return client.save(attrs, options); + }; + ClientsSettingsView.prototype.changePass = function(e) { + e.preventDefault(); + $(e.currentTarget).hide(); + return $("#password").show(); + }; + ClientsSettingsView.prototype.processPicUpload = function(e) { + e.preventDefault(); + this.ShowSpinner("submit"); + return $.ajaxFileUpload({ + url: API + '/user_pictures', + secureuri: false, + fileElementId: 'picture', + data: { + token: USER.token + }, + dataType: 'json', + complete: __bind(function(data, status) { + this.HideSpinner(); + if (status === 'success') { + this.ShowSuccess(t("Picture Update Succeeded")); + return this.RefreshUserInfo(__bind(function() { + return $("#settingsProfPic").attr("src", USER.picture_url + ("?" + (Math.floor(Math.random() * 1000)))); + }, this)); + } else { + if (data.error) { + return this.ShowError(data.error); + } else { + return this.ShowError("Picture Update Failed"); + } + } + }, this) + }); + }; + return ClientsSettingsView; + })(); +}).call(this); +}, "views/clients/sign_up": function(exports, require, module) {(function() { + var clientsSignUpTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + clientsSignUpTemplate = require('templates/clients/sign_up'); + exports.ClientsSignUpView = (function() { + __extends(ClientsSignUpView, UberView); + function ClientsSignUpView() { + ClientsSignUpView.__super__.constructor.apply(this, arguments); + } + ClientsSignUpView.prototype.id = 'signup_view'; + ClientsSignUpView.prototype.className = 'view_container'; + ClientsSignUpView.prototype.initialize = function() { + this.mixin(require('web-lib/mixins/i18n_phone_form').i18nPhoneForm); + return $('#location_country').live('change', function() { + if (!$('#mobile').val()) { + return $('#mobile_country').find("option[value=" + ($(this).val()) + "]").attr('selected', 'selected').end().trigger('change'); + } + }); + }; + ClientsSignUpView.prototype.events = { + 'submit form': 'signup', + 'click button': 'signup', + 'change #card_number': 'showCardType', + 'change #location_country': 'countryChange' + }; + ClientsSignUpView.prototype.render = function(invite) { + this.HideSpinner(); + $(this.el).html(clientsSignUpTemplate({ + invite: invite + })); + return this; + }; + ClientsSignUpView.prototype.signup = function(e) { + var $el, attrs, client, error_messages, options; + e.preventDefault(); + $el = $("form"); + $el.find('#terms_error').hide(); + if (!$el.find('#signup_terms input[type=checkbox]').attr('checked')) { + $('#spinner.submit').hide(); + $el.find('#terms_error').show(); + return; + } + error_messages = $el.find('.error_message').html(""); + attrs = { + first_name: $el.find('#first_name').val(), + last_name: $el.find('#last_name').val(), + email: $el.find('#email').val(), + password: $el.find('#password').val(), + location_country: $el.find('#location_country option:selected').attr('data-iso2'), + location: $el.find('#location').val(), + language: $el.find('#language').val(), + mobile_country: $el.find('#mobile_country option:selected').attr('data-iso2'), + mobile: $el.find('#mobile').val(), + card_number: $el.find('#card_number').val(), + card_expiration_month: $el.find('#card_expiration_month').val(), + card_expiration_year: $el.find('#card_expiration_year').val(), + card_code: $el.find('#card_code').val(), + use_case: $el.find('#use_case').val(), + promotion_code: $el.find('#promotion_code').val() + }; + options = { + statusCode: { + 200: function(response) { + $.cookie('token', response.token); + amplify.store('USERjson', response); + app.refreshMenu(); + return app.routers.clients.navigate('!/dashboard', true); + }, + 406: function(e) { + var error, errors, _i, _len, _ref, _results; + errors = JSON.parse(e.responseText); + _ref = _.keys(errors); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + error = _ref[_i]; + _results.push($('#' + error).parent().find('span').html($('#' + error).parent().find('span').html() + " " + errors[error])); + } + return _results; + } + }, + complete: __bind(function(response) { + return this.HideSpinner(); + }, this) + }; + client = new app.models.client; + $('.spinner#submit').show(); + return client.save(attrs, options); + }; + ClientsSignUpView.prototype.countryChange = function(e) { + var $e; + $e = $(e.currentTarget); + return $("#mobile_country").val($e.val()).trigger('change'); + }; + ClientsSignUpView.prototype.showCardType = function(e) { + var $el, reAmerica, reDiscover, reMaster, reVisa, validCard; + reVisa = /^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/; + reMaster = /^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/; + reAmerica = /^6011-?\d{4}-?\d{4}-?\d{4}$/; + reDiscover = /^3[4,7]\d{13}$/; + $el = $("#card_logos_signup"); + validCard = false; + if (e.currentTarget.value.match(reVisa)) { + $el.find("#overlay_left").css('width', "0px"); + return $el.find("#overlay_right").css('width', "75%"); + } else if (e.currentTarget.value.match(reMaster)) { + $el.find("#overlay_left").css('width', "25%"); + return $el.find("#overlay_right").css('width', "50%"); + } else if (e.currentTarget.value.match(reAmerica)) { + $el.find("#overlay_left").css('width', "75%"); + $el.find("#overlay_right").css('width', "0px"); + return console.log("amex"); + } else if (e.currentTarget.value.match(reDiscover)) { + $el.find("#overlay_left").css('width', "50%"); + return $el.find("#overlay_right").css('width', "25%"); + } else { + $el.find("#overlay_left").css('width', "0px"); + return $el.find("#overlay_right").css('width', "0px"); + } + }; + return ClientsSignUpView; + })(); +}).call(this); +}, "views/clients/trip_detail": function(exports, require, module) {(function() { + var clientsTripDetailTemplate; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsTripDetailTemplate = require('templates/clients/trip_detail'); + exports.TripDetailView = (function() { + __extends(TripDetailView, UberView); + function TripDetailView() { + this.resendReceipt = __bind(this.resendReceipt, this); + TripDetailView.__super__.constructor.apply(this, arguments); + } + TripDetailView.prototype.id = 'trip_detail_view'; + TripDetailView.prototype.className = 'view_container'; + TripDetailView.prototype.events = { + 'click a#fare_review': 'showFareReview', + 'click #fare_review_hide': 'hideFareReview', + 'submit #form_review_form': 'submitFareReview', + 'click #submit_fare_review': 'submitFareReview', + 'click .resendReceipt': 'resendReceipt' + }; + TripDetailView.prototype.render = function(id) { + if (id == null) { + id = 'invalid'; + } + this.ReadUserInfo(); + this.HideSpinner(); + this.model = new app.models.trip({ + id: id + }); + this.model.fetch({ + data: { + relationships: 'points,driver,city.country' + }, + dataType: 'json', + success: __bind(function() { + var trip; + trip = this.model; + $(this.el).html(clientsTripDetailTemplate({ + trip: trip + })); + this.RequireMaps(__bind(function() { + var bounds, endPos, map, myOptions, path, polyline, startPos; + bounds = new google.maps.LatLngBounds(); + path = []; + _.each(this.model.get('points'), __bind(function(point) { + path.push(new google.maps.LatLng(point.lat, point.lng)); + return bounds.extend(_.last(path)); + }, this)); + myOptions = { + zoom: 12, + center: path[0], + mapTypeId: google.maps.MapTypeId.ROADMAP, + zoomControl: false, + rotateControl: false, + panControl: false, + mapTypeControl: false, + scrollwheel: false + }; + map = new google.maps.Map(document.getElementById("trip_details_map"), myOptions); + map.fitBounds(bounds); + startPos = new google.maps.Marker({ + position: _.first(path), + map: map, + title: t("Trip started here"), + icon: 'https://uber-static.s3.amazonaws.com/marker_start.png' + }); + endPos = new google.maps.Marker({ + position: _.last(path), + map: map, + title: t("Trip ended here"), + icon: 'https://uber-static.s3.amazonaws.com/marker_end.png' + }); + startPos.setMap(map); + endPos.setMap(map); + polyline = new google.maps.Polyline({ + path: path, + strokeColor: '#003F87', + strokeOpacity: 1, + strokeWeight: 5 + }); + return polyline.setMap(map); + }, this)); + return this.HideSpinner(); + }, this) + }); + this.ShowSpinner('load'); + this.delegateEvents(); + return this; + }; + TripDetailView.prototype.showFareReview = function(e) { + e.preventDefault(); + $('#fare_review_box').slideDown(); + return $('#fare_review').hide(); + }; + TripDetailView.prototype.hideFareReview = function(e) { + e.preventDefault(); + $('#fare_review_box').slideUp(); + return $('#fare_review').show(); + }; + TripDetailView.prototype.submitFareReview = function(e) { + var attrs, errorMessage, id, options; + e.preventDefault(); + errorMessage = $(".error_message"); + errorMessage.hide(); + id = $("#tripid").val(); + this.model = new app.models.trip({ + id: id + }); + attrs = { + note: $('#form_review_message').val(), + note_type: 'client_fare_review' + }; + options = { + success: __bind(function(response) { + $(".success_message").fadeIn(); + return $("#fare_review_form_wrapper").slideUp(); + }, this), + error: __bind(function(error) { + return errorMessage.fadeIn(); + }, this) + }; + return this.model.save(attrs, options); + }; + TripDetailView.prototype.resendReceipt = function(e) { + var $e; + e.preventDefault(); + $e = $(e.currentTarget); + this.$(".resendReceiptSuccess").empty().show(); + this.$(".resentReceiptError").empty().show(); + e.preventDefault(); + $('#spinner').show(); + return $.ajax('/api/trips/func/resend_receipt', { + data: { + token: $.cookie('token'), + trip_id: this.model.id + }, + type: 'POST', + complete: __bind(function(xhr) { + var response; + response = JSON.parse(xhr.responseText); + $('#spinner').hide(); + switch (xhr.status) { + case 200: + this.$(".resendReceiptSuccess").html("Receipt has been emailed"); + return this.$(".resendReceiptSuccess").fadeOut(2000); + default: + this.$(".resendReceiptError").html("Receipt has failed to be emailed"); + return this.$(".resendReceiptError").fadeOut(2000); + } + }, this) + }); + }; + return TripDetailView; + })(); +}).call(this); +}, "views/shared/menu": function(exports, require, module) {(function() { + var menuTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + menuTemplate = require('templates/shared/menu'); + exports.SharedMenuView = (function() { + __extends(SharedMenuView, Backbone.View); + function SharedMenuView() { + SharedMenuView.__super__.constructor.apply(this, arguments); + } + SharedMenuView.prototype.id = 'menu_view'; + SharedMenuView.prototype.render = function() { + var type; + if ($.cookie('token') === null) { + type = 'guest'; + } else { + type = 'client'; + } + $(this.el).html(menuTemplate({ + type: type + })); + return this; + }; + return SharedMenuView; + })(); +}).call(this); +}, "web-lib/collections/countries": function(exports, require, module) {(function() { + var UberCollection; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + UberCollection = require('web-lib/uber_collection').UberCollection; + exports.CountriesCollection = (function() { + __extends(CountriesCollection, UberCollection); + function CountriesCollection() { + CountriesCollection.__super__.constructor.apply(this, arguments); + } + CountriesCollection.prototype.model = app.models.country; + CountriesCollection.prototype.url = '/countries'; + return CountriesCollection; + })(); +}).call(this); +}, "web-lib/collections/vehicle_types": function(exports, require, module) {(function() { + var UberCollection, vehicleType, _ref; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + UberCollection = require('web-lib/uber_collection').UberCollection; + vehicleType = (typeof app !== "undefined" && app !== null ? (_ref = app.models) != null ? _ref.vehicleType : void 0 : void 0) || require('models/vehicle_type').VehicleType; + exports.VehicleTypesCollection = (function() { + __extends(VehicleTypesCollection, UberCollection); + function VehicleTypesCollection() { + VehicleTypesCollection.__super__.constructor.apply(this, arguments); + } + VehicleTypesCollection.prototype.model = vehicleType; + VehicleTypesCollection.prototype.url = '/vehicle_types'; + VehicleTypesCollection.prototype.defaultColumns = ['id', 'created_at', 'updated_at', 'deleted_at', 'created_by_user_id', 'updated_by_user_id', 'city_id', 'type', 'make', 'model', 'capacity', 'minimum_year', 'actions']; + VehicleTypesCollection.prototype.tableColumns = function(cols) { + var actions, c, capacity, city_id, columnValues, created_at, created_by_user_id, deleted_at, headerRow, id, make, minimum_year, model, type, updated_at, updated_by_user_id, _i, _len; + id = { + sTitle: 'Id' + }; + created_at = { + sTitle: 'Created At (UTC)', + 'sType': 'string' + }; + updated_at = { + sTitle: 'Updated At (UTC)', + 'sType': 'string' + }; + deleted_at = { + sTitle: 'Deleted At (UTC)', + 'sType': 'string' + }; + created_by_user_id = { + sTitle: 'Created By' + }; + updated_by_user_id = { + sTitle: 'Updated By' + }; + city_id = { + sTitle: 'City' + }; + type = { + sTitle: 'Type' + }; + make = { + sTitle: 'Make' + }; + model = { + sTitle: 'Model' + }; + capacity = { + sTitle: 'Capacity' + }; + minimum_year = { + sTitle: 'Min. Year' + }; + actions = { + sTitle: 'Actions' + }; + columnValues = { + id: id, + created_at: created_at, + updated_at: updated_at, + deleted_at: deleted_at, + created_by_user_id: created_by_user_id, + updated_by_user_id: updated_by_user_id, + city_id: city_id, + type: type, + make: make, + model: model, + capacity: capacity, + minimum_year: minimum_year, + actions: actions + }; + headerRow = []; + for (_i = 0, _len = cols.length; _i < _len; _i++) { + c = cols[_i]; + if (columnValues[c]) { + headerRow.push(columnValues[c]); + } + } + return headerRow; + }; + return VehicleTypesCollection; + })(); +}).call(this); +}, "web-lib/helpers": function(exports, require, module) {(function() { + var __indexOf = Array.prototype.indexOf || function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (this[i] === item) return i; + } + return -1; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + exports.helpers = { + pin: function(num, color) { + if (color == null) { + color = 'FF0000'; + } + return ""; + }, + reverseGeocode: function(latitude, longitude) { + if (latitude && longitude) { + return "" + latitude + ", " + longitude + ""; + } else { + return ''; + } + }, + linkedName: function(model) { + var first_name, id, last_name, role, url; + role = model.role || model.get('role'); + id = model.id || model.get('id'); + first_name = model.first_name || model.get('first_name'); + last_name = model.last_name || model.get('last_name'); + url = "/" + role + "s/" + id; + return "" + first_name + " " + last_name + ""; + }, + linkedVehicle: function(vehicle, vehicleType) { + return " " + (vehicleType != null ? vehicleType.get('make') : void 0) + " " + (vehicleType != null ? vehicleType.get('model') : void 0) + " " + (vehicle.get('year')) + " "; + }, + linkedUserId: function(userType, userId) { + return "" + userType + " " + userId + ""; + }, + timeDelta: function(start, end) { + var delta; + if (typeof start === 'string') { + start = this.parseDate(start); + } + if (typeof end === 'string') { + end = this.parseDate(end); + } + if (end && start) { + delta = end.getTime() - start.getTime(); + return this.formatSeconds(delta / 1000); + } else { + return '00:00'; + } + }, + formatSeconds: function(s) { + var minutes, seconds; + s = Math.floor(s); + minutes = Math.floor(s / 60); + seconds = s - minutes * 60; + return "" + (this.leadingZero(minutes)) + ":" + (this.leadingZero(seconds)); + }, + formatCurrency: function(strValue, reverseSign, currency) { + var currency_locale, lc, mf; + if (reverseSign == null) { + reverseSign = false; + } + if (currency == null) { + currency = null; + } + strValue = String(strValue); + if (reverseSign) { + strValue = ~strValue.indexOf('-') ? strValue.split('-').join('') : ['-', strValue].join(''); + } + currency_locale = i18n.currencyToLocale[currency]; + try { + if (!(currency_locale != null) || currency_locale === i18n.locale) { + return i18n.jsworld.mf.format(strValue); + } else { + lc = new jsworld.Locale(POSIX_LC[currency_locale]); + mf = new jsworld.MonetaryFormatter(lc); + return mf.format(strValue); + } + } catch (error) { + i18n.log(error); + return strValue; + } + }, + formatTripFare: function(trip, type) { + var _ref, _ref2; + if (type == null) { + type = "fare"; + } + if (!trip.get('fare')) { + return 'n/a'; + } + if (((_ref = trip.get('fare_breakdown_local')) != null ? _ref.currency : void 0) != null) { + return app.helpers.formatCurrency(trip.get("" + type + "_local"), false, (_ref2 = trip.get('fare_breakdown_local')) != null ? _ref2.currency : void 0); + } else if (trip.get("" + type + "_string") != null) { + return trip.get("" + type + "_string"); + } else if (trip.get("" + type + "_local") != null) { + return trip.get("" + type + "_local"); + } else { + return 'n/a'; + } + }, + formatPhoneNumber: function(phoneNumber, countryCode) { + if (countryCode == null) { + countryCode = "+1"; + } + if (phoneNumber != null) { + phoneNumber = String(phoneNumber); + switch (countryCode) { + case '+1': + return countryCode + ' ' + phoneNumber.substring(0, 3) + '-' + phoneNumber.substring(3, 6) + '-' + phoneNumber.substring(6, 10); + case '+33': + return countryCode + ' ' + phoneNumber.substring(0, 1) + ' ' + phoneNumber.substring(1, 3) + ' ' + phoneNumber.substring(3, 5) + ' ' + phoneNumber.substring(5, 7) + ' ' + phoneNumber.substring(7, 9); + default: + countryCode + phoneNumber; + } + } + return "" + countryCode + " " + phoneNumber; + }, + parseDate: function(d, cityTime, tz) { + var city_filter, parsed, _ref; + if (cityTime == null) { + cityTime = true; + } + if (tz == null) { + tz = null; + } + if (((_ref = !d.substr(-6, 1)) === '+' || _ref === '-') || d.length === 19) { + d += '+00:00'; + } + if (/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})/.test(d)) { + parsed = d.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/); + d = new Date(); + d.setUTCFullYear(parsed[1]); + d.setUTCMonth(parsed[2] - 1); + d.setUTCDate(parsed[3]); + d.setUTCHours(parsed[4]); + d.setUTCMinutes(parsed[5]); + d.setUTCSeconds(parsed[6]); + } else { + d = Date.parse(d); + } + if (typeof d === 'number') { + d = new Date(d); + } + d = new timezoneJS.Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), 'Etc/UTC'); + if (tz) { + d.convertToTimezone(tz); + } else if (cityTime) { + city_filter = $.cookie('city_filter'); + if (city_filter) { + tz = $("#city_filter option[value=" + city_filter + "]").attr('data-timezone'); + if (tz) { + d.convertToTimezone(tz); + } + } + } + return d; + }, + dateToTimezone: function(d) { + var city_filter, tz; + d = new timezoneJS.Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), 'Etc/UTC'); + city_filter = $.cookie('city_filter'); + if (city_filter) { + tz = $("#city_filter option[value=" + city_filter + "]").attr('data-timezone'); + d.convertToTimezone(tz); + } + return d; + }, + fixAMPM: function(d, formatted) { + if (d.hours >= 12) { + return formatted.replace(/\b[AP]M\b/, 'PM'); + } else { + return formatted.replace(/\b[AP]M\b/, 'AM'); + } + }, + formatDate: function(d, time, timezone) { + var formatted; + if (time == null) { + time = true; + } + if (timezone == null) { + timezone = null; + } + d = this.parseDate(d, true, timezone); + formatted = time ? ("" + (i18n.jsworld.dtf.formatDate(d)) + " ") + this.formatTime(d, d.getTimezoneInfo()) : i18n.jsworld.dtf.formatDate(d); + return this.fixAMPM(d, formatted); + }, + formatDateLong: function(d, time, timezone) { + if (time == null) { + time = true; + } + if (timezone == null) { + timezone = null; + } + d = this.parseDate(d, true, timezone); + timezone = d.getTimezoneInfo().tzAbbr; + if (time) { + return (i18n.jsworld.dtf.formatDateTime(d)) + (" " + timezone); + } else { + return i18n.jsworld.dtf.formatDate(d); + } + }, + formatTimezoneJSDate: function(d) { + var day, hours, jsDate, minutes, month, year; + year = d.getFullYear(); + month = this.leadingZero(d.getMonth()); + day = this.leadingZero(d.getDate()); + hours = this.leadingZero(d.getHours()); + minutes = this.leadingZero(d.getMinutes()); + jsDate = new Date(year, month, day, hours, minutes, 0); + return jsDate.toDateString(); + }, + formatTime: function(d, timezone) { + var formatted; + if (timezone == null) { + timezone = null; + } + formatted = ("" + (i18n.jsworld.dtf.formatTime(d))) + (timezone != null ? " " + (timezone != null ? timezone.tzAbbr : void 0) : ""); + return this.fixAMPM(d, formatted); + }, + formatISODate: function(d) { + var pad; + pad = function(n) { + if (n < 10) { + return '0' + n; + } + return n; + }; + return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + 'Z'; + }, + formatExpDate: function(d) { + var month, year; + d = this.parseDate(d); + year = d.getFullYear(); + month = this.leadingZero(d.getMonth() + 1); + return "" + year + "-" + month; + }, + formatLatLng: function(lat, lng, precision) { + if (precision == null) { + precision = 8; + } + return parseFloat(lat).toFixed(precision) + ',' + parseFloat(lng).toFixed(precision); + }, + leadingZero: function(num) { + if (num < 10) { + return "0" + num; + } else { + return num; + } + }, + roundNumber: function(num, dec) { + return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec); + }, + notesToHTML: function(notes) { + var i, note, notesHTML, _i, _len; + notesHTML = ''; + i = 1; + if (notes) { + for (_i = 0, _len = notes.length; _i < _len; _i++) { + note = notes[_i]; + notesHTML += "" + note['userid'] + "     " + (this.formatDate(note['created_at'])) + "

" + note['note'] + "

"; + notesHTML += "
"; + } + } + return notesHTML.replace("'", '"e'); + }, + formatPhone: function(n) { + var parts, phone, regexObj; + n = "" + n; + regexObj = /^(?:\+?1[-. ]?)?(?:\(?([0-9]{3})\)?[-. ]?)?([0-9]{3})[-. ]?([0-9]{4})$/; + if (regexObj.test(n)) { + parts = n.match(regexObj); + phone = ""; + if (parts[1]) { + phone += "(" + parts[1] + ") "; + } + phone += "" + parts[2] + "-" + parts[3]; + } else { + phone = n; + } + return phone; + }, + usStates: ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'District of Columbia', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'], + onboardingPages: ['applied', 'ready_to_interview', 'pending_interview', 'interviewed', 'accepted', 'ready_to_onboard', 'pending_onboarding', 'active', 'waitlisted', 'rejected'], + driverBreadCrumb: function(loc, model) { + var onboardingPage, out, _i, _len, _ref; + out = "Drivers > "; + if (!(model != null)) { + out += ""; + } else { + out += "" + (this.onboardingUrlToName(model.get('driver_status'))) + ""; + out += " > " + (this.linkedName(model)) + " (" + (model.get('role')) + ") #" + (model.get('id')); + } + return out; + }, + onboardingUrlToName: function(url) { + return url != null ? url.replace(/_/g, " ").replace(/(^|\s)([a-z])/g, function(m, p1, p2) { + return p1 + p2.toUpperCase(); + }) : void 0; + }, + formatVehicle: function(vehicle) { + if (vehicle.get('make') && vehicle.get('model') && vehicle.get('license_plate')) { + return "" + (vehicle.get('make')) + " " + (vehicle.get('model')) + " (" + (vehicle.get('license_plate')) + ")"; + } + }, + docArbitraryFields: function(docName, cityDocs) { + var doc, field, out, _i, _j, _len, _len2, _ref; + out = ""; + for (_i = 0, _len = cityDocs.length; _i < _len; _i++) { + doc = cityDocs[_i]; + if (doc.name === docName && __indexOf.call(_.keys(doc), "metaFields") >= 0) { + _ref = doc.metaFields; + for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) { + field = _ref[_j]; + out += "" + field.label + ":
"; + } + } + } + return out; + }, + capitaliseFirstLetter: function(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + }, + createDocUploadForm: function(docName, driverId, vehicleId, cityMeta, vehicleName, expirationRequired) { + var ddocs, expDropdowns, pdocs, vdocs; + if (driverId == null) { + driverId = "None"; + } + if (vehicleId == null) { + vehicleId = "None"; + } + if (cityMeta == null) { + cityMeta = []; + } + if (vehicleName == null) { + vehicleName = false; + } + if (expirationRequired == null) { + expirationRequired = false; + } + ddocs = cityMeta["driverRequiredDocs"] || []; + pdocs = cityMeta["partnerRequiredDocs"] || []; + vdocs = cityMeta["vehicleRequiredDocs"] || []; + expDropdowns = "Expiration Date:\n -\n"; + return " \n
\n \n \n \n\n
\n " + (vehicleName ? vehicleName : "") + " " + docName + "\n
\n\n
\n \n
\n\n
\n " + (expirationRequired ? expDropdowns : "") + "\n
\n\n
\n " + (app.helpers.docArbitraryFields(docName, _.union(ddocs, pdocs, vdocs))) + "\n
\n\n
\n \n
\n\n
\n"; + }, + countrySelector: function(name, options) { + var countries, countryCodePrefix, defaultOptions; + if (options == null) { + options = {}; + } + defaultOptions = { + selectedKey: 'telephone_code', + selectedValue: '+1', + silent: false + }; + _.extend(defaultOptions, options); + options = defaultOptions; + countries = new app.collections.countries(); + countries.fetch({ + data: { + limit: 300 + }, + success: function(countries) { + var $option, $select, country, selected, _i, _len, _ref; + selected = false; + _ref = countries.models || []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + country = _ref[_i]; + $select = $("select[name=" + name + "]"); + $option = $('').val(country.id).attr('data-iso2', country.get('iso2')).attr('data-prefix', country.get('telephone_code')).html(country.get('name')); + if (country.get(options.selectedKey) === options.selectedValue && !selected) { + selected = true; + $option.attr('selected', 'selected'); + } + $select.append($option); + } + if (selected && !options.silent) { + return $select.val(options.selected).trigger('change'); + } + } + }); + countryCodePrefix = options.countryCodePrefix ? "data-country-code-prefix='" + options.countryCodePrefix + "'" : ''; + return ""; + }, + missingDocsOnDriver: function(driver) { + var city, docsReq, documents, partnerDocs; + city = driver.get('city'); + documents = driver.get('documents'); + if ((city != null) && (documents != null)) { + docsReq = _.pluck(city != null ? city.get('meta')["driverRequiredDocs"] : void 0, "name"); + if (driver.get('role') === "partner") { + partnerDocs = _.pluck(city != null ? city.get('meta')["partnerRequiredDocs"] : void 0, "name"); + docsReq = _.union(docsReq, partnerDocs); + } + return _.reject(docsReq, __bind(function(doc) { + return __indexOf.call((documents != null ? documents.pluck("name") : void 0) || [], doc) >= 0; + }, this)); + } else { + return []; + } + } + }; +}).call(this); +}, "web-lib/i18n": function(exports, require, module) {(function() { + exports.i18n = { + defaultLocale: 'en_US', + cookieName: '_LOCALE_', + locales: { + 'en_US': "English (US)", + 'fr_FR': "Français" + }, + currencyToLocale: { + 'USD': 'en_US', + 'EUR': 'fr_FR' + }, + logglyKey: 'd2d5a9bc-7ebe-4538-a180-81e62c705b1b', + logglyHost: 'https://logs.loggly.com', + init: function() { + this.castor = new window.loggly({ + url: this.logglyHost + '/inputs/' + this.logglyKey + '?rt=1', + level: 'error' + }); + this.setLocale($.cookie(this.cookieName) || this.defaultLocale); + window.t = _.bind(this.t, this); + this.loadLocaleTranslations(this.locale); + if (!(this[this.defaultLocale] != null)) { + return this.loadLocaleTranslations(this.defaultLocale); + } + }, + loadLocaleTranslations: function(locale) { + var loadPaths, path, _i, _len, _results; + loadPaths = ['web-lib/translations/' + locale, 'web-lib/translations/' + locale.slice(0, 2), 'translations/' + locale, 'translations/' + locale.slice(0, 2)]; + _results = []; + for (_i = 0, _len = loadPaths.length; _i < _len; _i++) { + path = loadPaths[_i]; + locale = path.substring(path.lastIndexOf('/') + 1); + if (this[locale] == null) { + this[locale] = {}; + } + _results.push((function() { + try { + return _.extend(this[locale], require(path).translations); + } catch (error) { + + } + }).call(this)); + } + return _results; + }, + getLocale: function() { + return this.locale; + }, + setLocale: function(locale) { + var message, parts, _ref; + parts = locale.split('_'); + this.locale = parts[0].toLowerCase(); + if (parts.length > 1) { + this.locale += "_" + (parts[1].toUpperCase()); + } + if (this.locale) { + $.cookie(this.cookieName, this.locale, { + path: '/', + domain: '.uber.com' + }); + } + try { + ((_ref = this.jsworld) != null ? _ref : this.jsworld = {}).lc = new jsworld.Locale(POSIX_LC[this.locale]); + this.jsworld.mf = new jsworld.MonetaryFormatter(this.jsworld.lc); + this.jsworld.nf = new jsworld.NumericFormatter(this.jsworld.lc); + this.jsworld.dtf = new jsworld.DateTimeFormatter(this.jsworld.lc); + this.jsworld.np = new jsworld.NumericParser(this.jsworld.lc); + this.jsworld.mp = new jsworld.MonetaryParser(this.jsworld.lc); + return this.jsworld.dtp = new jsworld.DateTimeParser(this.jsworld.lc); + } catch (error) { + message = 'JsWorld error with locale: ' + this.locale; + return this.log({ + message: message, + error: error + }); + } + }, + getTemplate: function(id) { + var _ref, _ref2; + return ((_ref = this[this.locale]) != null ? _ref[id] : void 0) || ((_ref2 = this[this.locale.slice(0, 2)]) != null ? _ref2[id] : void 0); + }, + getTemplateDefault: function(id) { + var _ref, _ref2; + return ((_ref = this[this.defaultLocale]) != null ? _ref[id] : void 0) || ((_ref2 = this[this.defaultLocale.slice(0, 2)]) != null ? _ref2[id] : void 0); + }, + getTemplateOrDefault: function(id) { + return this.getTemplate(id) || this.getTemplateDefault(id); + }, + t: function(id, vars) { + var errStr, locale, template; + if (vars == null) { + vars = {}; + } + locale = this.getLocale(); + template = this.getTemplate(id); + if (template == null) { + if (/dev|test/.test(window.location.host)) { + template = "(?) " + id; + } else { + template = this.getTemplateDefault(id); + } + errStr = "Missing [" + locale + "] translation for [" + id + "] at [" + window.location.hash + "] - Default template is [" + template + "]"; + this.log({ + error: errStr, + locale: locale, + id: id, + defaultTemplate: template + }); + } + if (template) { + return _.template(template, vars); + } else { + return id; + } + }, + log: function(error) { + if (/dev/.test(window.location.host)) { + if ((typeof console !== "undefined" && console !== null ? console.log : void 0) != null) { + return console.log(error); + } + } else { + _.extend(error, { + host: window.location.host, + hash: window.location.hash + }); + return this.castor.error(JSON.stringify(error)); + } + } + }; +}).call(this); +}, "web-lib/mixins/i18n_phone_form": function(exports, require, module) {(function() { + exports.i18nPhoneForm = { + _events: { + 'change select[data-country-code-prefix]': 'setCountryCodePrefix' + }, + setCountryCodePrefix: function(e) { + var $el, prefix; + $el = $(e.currentTarget); + prefix = $el.find('option:selected').attr('data-prefix'); + return $("#" + ($el.attr('data-country-code-prefix'))).text(prefix); + } + }; +}).call(this); +}, "web-lib/models/country": function(exports, require, module) {(function() { + var UberModel; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + UberModel = require('web-lib/uber_model').UberModel; + exports.Country = (function() { + __extends(Country, UberModel); + function Country() { + Country.__super__.constructor.apply(this, arguments); + } + Country.prototype.url = function() { + if (this.id) { + return "/countries/" + this.id; + } else { + return '/countries'; + } + }; + return Country; + })(); +}).call(this); +}, "web-lib/models/vehicle_type": function(exports, require, module) {(function() { + var UberModel; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + UberModel = require('web-lib/uber_model').UberModel; + exports.VehicleType = (function() { + __extends(VehicleType, UberModel); + function VehicleType() { + this.toString = __bind(this.toString, this); + VehicleType.__super__.constructor.apply(this, arguments); + } + VehicleType.prototype.endpoint = 'vehicle_types'; + VehicleType.prototype.toTableRow = function(cols) { + var actions, c, capacity, city_id, columnValues, created_at, created_by_user_id, deleted_at, id, make, minimum_year, model, rows, type, updated_at, updated_by_user_id, _i, _len, _ref; + id = "" + (this.get('id')) + ""; + if (this.get('created_at')) { + created_at = app.helpers.formatDate(this.get('created_at')); + } + if (this.get('updated_at')) { + updated_at = app.helpers.formatDate(this.get('updated_at')); + } + if (this.get('deleted_at')) { + deleted_at = app.helpers.formatDate(this.get('deleted_at')); + } + created_by_user_id = "" + (this.get('created_by_user_id')) + ""; + updated_by_user_id = "" + (this.get('updated_by_user_id')) + ""; + city_id = (_ref = this.get('city')) != null ? _ref.get('display_name') : void 0; + type = this.get('type'); + make = this.get('make'); + model = this.get('model'); + capacity = this.get('capacity'); + minimum_year = this.get('minimum_year'); + actions = "Show"; + if (!this.get('deleted_at')) { + actions += " Edit"; + actions += " Delete"; + } + columnValues = { + id: id, + created_at: created_at, + updated_at: updated_at, + deleted_at: deleted_at, + created_by_user_id: created_by_user_id, + updated_by_user_id: updated_by_user_id, + city_id: city_id, + type: type, + make: make, + model: model, + capacity: capacity, + minimum_year: minimum_year, + actions: actions + }; + rows = []; + for (_i = 0, _len = cols.length; _i < _len; _i++) { + c = cols[_i]; + rows.push(columnValues[c] ? columnValues[c] : '-'); + } + return rows; + }; + VehicleType.prototype.toString = function() { + return this.get('make') + ' ' + this.get('model') + ' ' + this.get('type') + (" (" + (this.get('capacity')) + ")"); + }; + return VehicleType; + })(); +}).call(this); +}, "web-lib/templates/footer": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + var locale, title, _ref; + __out.push('\n\n\n\n\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "web-lib/translations/en": function(exports, require, module) {(function() { + exports.translations = { + "Info": "Info", + "Learn More": "Learn More", + "Pricing": "Pricing", + "FAQ": "FAQ", + "Support": "Support", + "Support & FAQ": "Support & FAQ", + "Contact Us": "Contact Us", + "Jobs": "Jobs", + "Phones": "Phones", + "Text Message": "Text Message", + "iPhone": "iPhone", + "Android": "Android", + "Drivers": "Drivers", + "Apply": "Apply", + "Sign In": "Sign In", + "Social": "Social", + "Twitter": "Twitter", + "Facebook": "Facebook", + "Blog": "Blog", + "Legal": "Legal", + "Company_Footer": "Company", + "Privacy Policy": "Privacy Policy", + "Terms": "Terms", + "Copyright © Uber Technologies, Inc.": "Copyright © Uber Technologies, Inc.", + "Language:": "Language:", + "Apply to Drive": "Apply to Drive", + "Expiration": "Expiration", + "Fare": "Fare", + "Driver": "Driver ", + "Dashboard": "Dashboard", + "Forgot Password": "Forgot Password", + "Trip Details": "Trip Details", + "Save": "Save", + "Cancel": "Cancel", + "Edit": "Edit", + "Password": "Password", + "First Name": "First Name", + "Last Name": "Last Name", + "Email Address": "Email Address", + "Submit": "Submit", + "Mobile Number": "Mobile Number", + "Zip Code": "Zip Code", + "Sign Out": "Sign Out", + "Confirm Email Message": "Attempting to confirm email...", + "Upload": "Upload", + "Rating": "Rating", + "Pickup Time": "Pickup Time", + "2011": "2011", + "2012": "2012", + "2013": "2013", + "2014": "2014", + "2015": "2015", + "2016": "2016", + "2017": "2017", + "2018": "2018", + "2019": "2019", + "2020": "2020", + "2021": "2021", + "2022": "2022", + "01": "01", + "02": "02", + "03": "03", + "04": "04", + "05": "05", + "06": "06", + "07": "07", + "08": "08", + "09": "09", + "10": "10", + "11": "11", + "12": "12" + }; +}).call(this); +}, "web-lib/translations/fr": function(exports, require, module) {(function() { + exports.translations = { + "Info": "Info", + "Learn More": "En Savoir Plus", + "Pricing": "Calcul du Prix", + "Support & FAQ": "Aide & FAQ", + "Contact Us": "Contactez Nous", + "Jobs": "Emplois", + "Phones": "Téléphones", + "Text Message": "SMS", + "iPhone": "iPhone", + "Android": "Android", + "Apply to Drive": "Candidature Chauffeur", + "Sign In": "Connexion", + "Social": "Contact", + "Twitter": "Twitter", + "Facebook": "Facebook", + "Blog": "Blog", + "Privacy Policy": "Protection des Données Personelles", + "Terms": "Conditions Générales", + "Copyright © Uber Technologies, Inc.": "© Uber, Inc.", + "Language:": "Langue:", + "Forgot Password": "Mot de passe oublié", + "Company_Footer": "À Propos d'Uber", + "Expiration": "Expiration", + "Fare": "Tarif", + "Driver": "Chauffeur", + "Drivers": "Chauffeurs", + "Dashboard": "Tableau de bord", + "Forgot Password": "Mot de passe oublié", + "Forgot Password?": "Mot de passe oublié?", + "Trip Details": "Détails de la course", + "Save": "Enregistrer", + "Cancel": "Annuler", + "Edit": "Modifier", + "Password": "Mot de passe", + "First Name": "Prénom", + "Last Name": "Nom", + "Email Address": "E-mail", + "Submit": "Soumettre", + "Mobile Number": "Téléphone Portable", + "Zip Code": "Code Postal", + "Sign Out": "Se déconnecter", + "Confirm Email Message": "E-mail de confirmation", + "Upload": "Télécharger", + "Rating": "Notation", + "Pickup Time": "Heure de prise en charge", + "2011": "2011", + "2012": "2012", + "2013": "2013", + "2014": "2014", + "2015": "2015", + "2016": "2016", + "2017": "2017", + "2018": "2018", + "2019": "2019", + "2020": "2020", + "2021": "2021", + "2022": "2022", + "01": "01", + "02": "02", + "03": "03", + "04": "04", + "05": "05", + "06": "06", + "07": "07", + "08": "08", + "09": "09", + "10": "10", + "11": "11", + "12": "12" + }; +}).call(this); +}, "web-lib/uber_collection": function(exports, require, module) {(function() { + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + exports.UberCollection = (function() { + __extends(UberCollection, Backbone.Collection); + function UberCollection() { + UberCollection.__super__.constructor.apply(this, arguments); + } + UberCollection.prototype.parse = function(data) { + var model, tmp, _i, _in, _len, _out; + _in = data.resources || data; + _out = []; + if (data.meta) { + this.meta = data.meta; + } + for (_i = 0, _len = _in.length; _i < _len; _i++) { + model = _in[_i]; + tmp = new this.model; + tmp.set(tmp.parse(model)); + _out.push(tmp); + } + return _out; + }; + UberCollection.prototype.isRenderable = function() { + if (this.models.length) { + return true; + } + }; + UberCollection.prototype.toTableRows = function(cols) { + var tableRows; + tableRows = []; + _.each(this.models, function(model) { + return tableRows.push(model.toTableRow(cols)); + }); + return tableRows; + }; + return UberCollection; + })(); +}).call(this); +}, "web-lib/uber_model": function(exports, require, module) {(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __indexOf = Array.prototype.indexOf || function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (this[i] === item) return i; + } + return -1; + }; + exports.UberModel = (function() { + __extends(UberModel, Backbone.Model); + function UberModel() { + this.refetch = __bind(this.refetch, this); + this.fetch = __bind(this.fetch, this); + this.save = __bind(this.save, this); + this.parse = __bind(this.parse, this); + UberModel.__super__.constructor.apply(this, arguments); + } + UberModel.prototype.endpoint = 'set_api_endpoint_in_subclass'; + UberModel.prototype.refetchOptions = {}; + UberModel.prototype.url = function(type) { + var endpoint_path; + endpoint_path = "/" + this.endpoint; + if (this.get('id')) { + return endpoint_path + ("/" + (this.get('id'))); + } else { + return endpoint_path; + } + }; + UberModel.prototype.isRenderable = function() { + var i, key, value, _ref; + i = 0; + _ref = this.attributes; + for (key in _ref) { + if (!__hasProp.call(_ref, key)) continue; + value = _ref[key]; + if (this.attributes.hasOwnProperty(key)) { + i += 1; + } + if (i > 1) { + return true; + } + } + return !(i === 1); + }; + UberModel.prototype.parse = function(response) { + var attrs, key, model, models, _i, _j, _k, _len, _len2, _len3, _ref, _ref2; + if (typeof response === 'object') { + _ref = _.intersection(_.keys(app.models), _.keys(response)); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + if (response[key]) { + attrs = this.parse(response[key]); + if (typeof attrs === 'object') { + response[key] = new app.models[key](attrs); + } + } + } + _ref2 = _.intersection(_.keys(app.collections), _.keys(response)); + for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { + key = _ref2[_j]; + models = response[key]; + if (_.isArray(models)) { + response[key] = new app.collections[key]; + for (_k = 0, _len3 = models.length; _k < _len3; _k++) { + model = models[_k]; + attrs = app.collections[key].prototype.model.prototype.parse(model); + response[key].add(new response[key].model(attrs)); + } + } + } + } + return response; + }; + UberModel.prototype.save = function(attributes, options) { + var attr, _i, _j, _len, _len2, _ref, _ref2; + if (options == null) { + options = {}; + } + _ref = _.intersection(_.keys(app.models), _.keys(this.attributes)); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + attr = _ref[_i]; + if (typeof this.get(attr) === "object") { + this.unset(attr, { + silent: true + }); + } + } + _ref2 = _.intersection(_.keys(app.collections), _.keys(this.attributes)); + for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { + attr = _ref2[_j]; + if (typeof this.get(attr) === "object") { + this.unset(attr, { + silent: true + }); + } + } + if ((options != null) && options.diff && (attributes != null) && attributes !== {}) { + attributes['id'] = this.get('id'); + attributes['token'] = this.get('token'); + this.clear({ + 'silent': true + }); + this.set(attributes, { + silent: true + }); + } + if (__indexOf.call(_.keys(options), "data") < 0 && __indexOf.call(_.keys(this.refetchOptions || {}), "data") >= 0) { + options.data = this.refetchOptions.data; + } + return Backbone.Model.prototype.save.call(this, attributes, options); + }; + UberModel.prototype.fetch = function(options) { + this.refetchOptions = options; + return Backbone.Model.prototype.fetch.call(this, options); + }; + UberModel.prototype.refetch = function() { + return this.fetch(this.refetchOptions); + }; + return UberModel; + })(); +}).call(this); +}, "web-lib/uber_router": function(exports, require, module) {(function() { + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + exports.UberRouter = (function() { + __extends(UberRouter, Backbone.Router); + function UberRouter() { + UberRouter.__super__.constructor.apply(this, arguments); + } + UberRouter.prototype.datePickers = function(format) { + if (format == null) { + format = "%Z-%m-%dT%H:%i:%s%:"; + } + $('.datepicker').AnyTime_noPicker(); + return $('.datepicker').AnyTime_picker({ + 'format': format, + 'formatUtcOffset': '%@' + }); + }; + UberRouter.prototype.autoGrowInput = function() { + return $('.editable input').autoGrowInput(); + }; + UberRouter.prototype.windowTitle = function(title) { + return $(document).attr('title', title); + }; + return UberRouter; + })(); +}).call(this); +}, "web-lib/uber_show_view": function(exports, require, module) {(function() { + var UberView; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + UberView = require('web-lib/uber_view').UberView; + exports.UberShowView = (function() { + __extends(UberShowView, UberView); + function UberShowView() { + UberShowView.__super__.constructor.apply(this, arguments); + } + UberShowView.prototype.view = 'show'; + UberShowView.prototype.events = { + 'click #edit': 'edit', + 'submit form': 'save', + 'click .cancel': 'cancel' + }; + UberShowView.prototype.errors = null; + UberShowView.prototype.showTemplate = null; + UberShowView.prototype.editTemplate = null; + UberShowView.prototype.initialize = function() { + if (this.init_hook) { + this.init_hook(); + } + _.bindAll(this, 'render'); + return this.model.bind('change', this.render); + }; + UberShowView.prototype.render = function() { + var $el; + $el = $(this.el); + this.selectView(); + if (this.view === 'show') { + $el.html(this.showTemplate({ + model: this.model + })); + } else if (this.view === 'edit') { + $el.html(this.editTemplate({ + model: this.model, + errors: this.errors || {}, + collections: this.collections || {} + })); + } else { + $el.html(this.newTemplate({ + model: this.model, + errors: this.errors || {}, + collections: this.collections || {} + })); + } + if (this.render_hook) { + this.render_hook(); + } + this.errors = null; + this.userIdsToLinkedNames(); + this.datePickers(); + return this.place(); + }; + UberShowView.prototype.selectView = function() { + var url; + if (this.options.urlRendering) { + url = window.location.hash; + if (url.match(/\/new/)) { + return this.view = 'new'; + } else if (url.match(/\/edit/)) { + return this.view = 'edit'; + } else { + return this.view = 'show'; + } + } + }; + UberShowView.prototype.edit = function(e) { + e.preventDefault(); + if (this.options.urlRendering) { + window.location.hash = '#/' + this.model.endpoint + '/' + this.model.get('id') + '/edit'; + } else { + this.view = 'edit'; + } + return this.model.change(); + }; + UberShowView.prototype.save = function(e) { + var attributes, ele, form_attrs, _i, _len, _ref; + e.preventDefault(); + attributes = $(e.currentTarget).serializeToJson(); + form_attrs = {}; + _ref = $('input[type="radio"]'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ele = _ref[_i]; + if ($(ele).is(':checked')) { + form_attrs[$(ele).attr('name')] = $(ele).attr('value'); + } + } + attributes = _.extend(attributes, form_attrs); + if (this.relationships) { + attributes = _.extend(attributes, { + relationships: this.relationships + }); + } + if (this.filter_attributes != null) { + this.filter_attributes(attributes); + } + return this.model.save(attributes, { + silent: true, + success: __bind(function(model) { + if (this.options.urlRendering) { + window.location.hash = '#/' + this.model.endpoint + '/' + this.model.get('id'); + } else { + this.view = 'show'; + } + return this.flash('success', "Uber save!"); + }, this), + statusCode: { + 406: __bind(function(xhr) { + this.errors = JSON.parse(xhr.responseText); + return this.flash('error', 'That was not Uber.'); + }, this) + }, + error: __bind(function(model, xhr) { + var code, message, responseJSON, responseText; + code = xhr.status; + responseText = xhr.responseText; + if (responseText) { + responseJSON = JSON.parse(responseText); + } + if (responseJSON && (typeof responseJSON === 'object') && (responseJSON.hasOwnProperty('error'))) { + message = responseJSON.error; + } + return this.flash('error', (code || 'Unknown') + ' error' + (': ' + message || '')); + }, this), + complete: __bind(function() { + return this.model.change(); + }, this) + }); + }; + UberShowView.prototype.cancel = function(e) { + e.preventDefault(); + if (this.options.urlRendering) { + window.location.hash = '#/' + this.model.endpoint + '/' + this.model.get('id'); + } else { + this.view = 'show'; + } + return this.model.fetch({ + silent: true, + complete: __bind(function() { + return this.model.change(); + }, this) + }); + }; + return UberShowView; + })(); +}).call(this); +}, "web-lib/uber_sync": function(exports, require, module) {(function() { + var methodType; + var __indexOf = Array.prototype.indexOf || function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (this[i] === item) return i; + } + return -1; + }; + methodType = { + create: 'POST', + update: 'PUT', + "delete": 'DELETE', + read: 'GET' + }; + exports.UberSync = function(method, model, options) { + var token; + options.type = methodType[method]; + options.url = _.isString(this.url) ? '/api' + this.url : '/api' + this.url(options.type); + options.data = _.extend({}, options.data); + if (__indexOf.call(_.keys(options.data), "city_id") < 0) { + if ($.cookie('city_filter')) { + _.extend(options.data, { + city_id: $.cookie('city_filter') + }); + } + } else { + delete options.data['city_id']; + } + if (options.type === 'POST' || options.type === 'PUT') { + _.extend(options.data, model.toJSON()); + } + token = $.cookie('token') ? $.cookie('token') : typeof USER !== "undefined" && USER !== null ? USER.get('token') : ""; + _.extend(options.data, { + token: token + }); + if (method === "delete") { + options.contentType = 'application/json'; + options.data = JSON.stringify(options.data); + } + return $.ajax(options); + }; +}).call(this); +}, "web-lib/uber_view": function(exports, require, module) {(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + exports.UberView = (function() { + __extends(UberView, Backbone.View); + function UberView() { + this.processDocumentUpload = __bind(this.processDocumentUpload, this); + UberView.__super__.constructor.apply(this, arguments); + } + UberView.prototype.className = 'view_container'; + UberView.prototype.hashId = function() { + return parseInt(location.hash.split('/')[2]); + }; + UberView.prototype.place = function(content) { + var $target; + $target = this.options.scope ? this.options.scope.find(this.options.selector) : $(this.options.selector); + $target[this.options.method || 'html'](content || this.el); + this.delegateEvents(); + $('#spinner').hide(); + return this; + }; + UberView.prototype.mixin = function(m, args) { + var events, self; + if (args == null) { + args = {}; + } + self = this; + events = m._events; + _.extend(this, m); + if (m.initialize) { + m.initialize(self, args); + } + return _.each(_.keys(events), function(key) { + var event, func, selector, split; + split = key.split(' '); + event = split[0]; + selector = split[1]; + func = events[key]; + return $(self.el).find(selector).live(event, function(e) { + return self[func](e); + }); + }); + }; + UberView.prototype.datePickers = function(format) { + if (format == null) { + format = "%Z-%m-%dT%H:%i:%s%:"; + } + $('.datepicker').AnyTime_noPicker(); + return $('.datepicker').AnyTime_picker({ + 'format': format, + 'formatUtcOffset': '%@' + }); + }; + UberView.prototype.dataTable = function(collection, selector, options, params, cols) { + var defaults; + if (selector == null) { + selector = 'table'; + } + if (options == null) { + options = {}; + } + if (params == null) { + params = {}; + } + if (cols == null) { + cols = []; + } + $(selector).empty(); + if (!cols.length) { + cols = collection.defaultColumns; + } + defaults = { + aoColumns: collection.tableColumns(cols), + bDestroy: true, + bSort: false, + bProcessing: true, + bFilter: false, + bServerSide: true, + bPaginate: true, + bScrollInfinite: true, + bScrollCollapse: true, + sScrollY: '600px', + iDisplayLength: 50, + fnServerData: function(source, data, callback) { + var defaultParams; + defaultParams = { + limit: data[4].value, + offset: data[3].value + }; + return collection.fetch({ + data: _.extend(defaultParams, params), + success: function() { + return callback({ + aaData: collection.toTableRows(cols), + iTotalRecords: collection.meta.count, + iTotalDisplayRecords: collection.meta.count + }); + }, + error: function() { + return new Error({ + message: 'Loading error.' + }); + } + }); + }, + fnRowCallback: function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { + $('[data-tooltip]', nRow).qtip({ + content: { + attr: 'data-tooltip' + }, + style: { + classes: "ui-tooltip-light ui-tooltip-rounded ui-tooltip-shadow" + } + }); + return nRow; + } + }; + return $(this.el).find(selector).dataTable(_.extend(defaults, options)); + }; + UberView.prototype.dataTableLocal = function(collection, selector, options, params, cols) { + var $dataTable, defaults; + if (selector == null) { + selector = 'table'; + } + if (options == null) { + options = {}; + } + if (params == null) { + params = {}; + } + if (cols == null) { + cols = []; + } + $(selector).empty(); + if (!cols.length || cols.length === 0) { + cols = collection.defaultColumns; + } + defaults = { + aaData: collection.toTableRows(cols), + aoColumns: collection.tableColumns(cols), + bDestroy: true, + bSort: false, + bProcessing: true, + bFilter: false, + bScrollInfinite: true, + bScrollCollapse: true, + sScrollY: '600px', + iDisplayLength: -1 + }; + $dataTable = $(this.el).find(selector).dataTable(_.extend(defaults, options)); + _.delay(__bind(function() { + if ($dataTable && $dataTable.length > 0) { + return $dataTable.fnAdjustColumnSizing(); + } + }, this), 1); + return $dataTable; + }; + UberView.prototype.reverseGeocode = function() { + var $el; + return ''; + $el = $(this.el); + return this.requireMaps(function() { + var geocoder; + geocoder = new google.maps.Geocoder(); + return $el.find('[data-point]').each(function() { + var $this, latLng, point; + $this = $(this); + point = JSON.parse($this.attr('data-point')); + latLng = new google.maps.LatLng(point.latitude, point.longitude); + return geocoder.geocode({ + latLng: latLng + }, function(data, status) { + if (status === google.maps.GeocoderStatus.OK) { + return $this.text(data[0].formatted_address); + } + }); + }); + }); + }; + UberView.prototype.userIdsToLinkedNames = function() { + var $el; + $el = $(this.el); + return $el.find('a[data-user-id][data-user-type]').each(function() { + var $this, user, userType; + $this = $(this); + userType = $this.attr('data-user-type') === 'user' ? 'client' : $this.attr('data-user-type'); + user = new app.models[userType]({ + id: $this.attr('data-user-id') + }); + return user.fetch({ + success: function(user) { + return $this.html(app.helpers.linkedName(user)).attr('href', "!/" + user.role + "s/" + user.id); + }, + error: function() { + if ($this.attr('data-user-type') === 'user') { + user = new app.models['driver']({ + id: $this.attr('data-user-id') + }); + return user.fetch({ + success: function(user) { + return $this.html(app.helpers.linkedName(user)).attr('href', "!/driver/" + user.id); + } + }); + } + } + }); + }); + }; + UberView.prototype.selectedCity = function() { + var $selected, city, cityFilter; + cityFilter = $.cookie('city_filter'); + $selected = $("#city_filter option[value=" + cityFilter + "]"); + if (city_filter && $selected.length) { + return city = { + lat: parseFloat($selected.attr('data-lat')), + lng: parseFloat($selected.attr('data-lng')), + timezone: $selected.attr('data-timezone') + }; + } else { + return city = { + lat: 37.775, + lng: -122.45, + timezone: 'Etc/UTC' + }; + } + }; + UberView.prototype.updateModel = function(e, success) { + var $el, attrs, model, self; + e.preventDefault(); + $el = $(e.currentTarget); + self = this; + model = new this.model.__proto__.constructor({ + id: this.model.id + }); + attrs = {}; + $el.find('[name]').each(function() { + var $this; + $this = $(this); + return attrs["" + ($this.attr('name'))] = $this.val(); + }); + self.model.set(attrs); + $el.find('span.error').text(''); + return model.save(attrs, { + complete: function(xhr) { + var response; + response = JSON.parse(xhr.responseText); + switch (xhr.status) { + case 200: + self.model = model; + $el.find('[name]').val(''); + if (success) { + return success(); + } + break; + case 406: + return _.each(response, function(error, field) { + return $el.find("[name=" + field + "]").parent().find('span.error').text(error); + }); + default: + return this.unanticipatedError(response); + } + } + }); + }; + UberView.prototype.autoUpdateModel = function(e) { + var $el, arg, model, self, val; + $el = $(e.currentTarget); + val = $el.val(); + self = this; + if (val !== this.model.get($el.attr('id'))) { + arg = {}; + arg[$el.attr('id')] = $el.is(':checkbox') ? $el.is(':checked') ? 1 : 0 : val; + $('.editable span').empty(); + this.model.set(arg); + model = new this.model.__proto__.constructor({ + id: this.model.id + }); + return model.save(arg, { + complete: function(xhr) { + var key, response, _i, _len, _ref, _results; + response = JSON.parse(xhr.responseText); + switch (xhr.status) { + case 200: + self.flash('success', 'Saved!'); + return $el.blur(); + case 406: + self.flash('error', 'That was not Uber.'); + _ref = _.keys(response); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _results.push($el.parent().find('span').html(response[key])); + } + return _results; + break; + default: + return self.unanticipatedError; + } + } + }); + } + }; + UberView.prototype.unanticipatedError = function(response) { + return self.flash('error', response); + }; + UberView.prototype.flash = function(type, text) { + var $banner; + $banner = $("." + type); + $banner.find('p').text(text).end().css('border', '1px solid #999').animate({ + top: 0 + }, 500); + return setTimeout(function() { + return $banner.animate({ + top: -$banner.outerHeight() + }, 500); + }, 3000); + }; + UberView.prototype.requireMaps = function(callback) { + if (typeof google !== 'undefined' && google.maps) { + return callback(); + } else { + return $.getScript("https://www.google.com/jsapi?key=" + CONFIG.googleJsApiKey, function() { + return google.load('maps', 3, { + callback: callback, + other_params: 'sensor=false&language=en' + }); + }); + } + }; + UberView.prototype.select_drop_down = function(model, key) { + var value; + value = model.get(key); + if (value) { + return $("select[id='" + key + "'] option[value='" + value + "']").attr('selected', 'selected'); + } + }; + UberView.prototype.processDocumentUpload = function(e) { + var $fi, $form, arbData, curDate, data, expDate, expM, expY, expiration, fileElementId, invalid; + e.preventDefault(); + $form = $(e.currentTarget); + $fi = $("input[type=file]", $form); + $(".validationError").removeClass("validationError"); + if (!$fi.val()) { + return $fi.addClass("validationError"); + } else { + fileElementId = $fi.attr('id'); + expY = $("select[name=expiration-year]", $form).val(); + expM = $("select[name=expiration-month]", $form).val(); + invalid = false; + if (expY && expM) { + expDate = new Date(expY, expM, 28); + curDate = new Date(); + if (expDate < curDate) { + invalid = true; + $(".expiration", $form).addClass("validationError"); + } + expiration = "" + expY + "-" + expM + "-28T23:59:59Z"; + } + arbData = {}; + $(".arbitraryField", $form).each(__bind(function(i, e) { + arbData[$(e).attr('name')] = $(e).val(); + if ($(e).val() === "") { + invalid = true; + return $(e).addClass("validationError"); + } + }, this)); + if (!invalid) { + data = { + token: $.cookie('token') || USER.get('token'), + name: $("input[name=fileName]", $form).val(), + meta: escape(JSON.stringify(arbData)), + user_id: $("input[name=driver_id]", $form).val(), + vehicle_id: $("input[name=vehicle_id]", $form).val() + }; + if (expiration) { + data['expiration'] = expiration; + } + $("#spinner").show(); + return $.ajaxFileUpload({ + url: '/api/documents', + secureuri: false, + fileElementId: fileElementId, + data: data, + complete: __bind(function(resp, status) { + var key, _i, _len, _ref, _results; + $("#spinner").hide(); + if (status === "success") { + if (this.model) { + this.model.refetch(); + } else { + USER.refetch(); + } + } + if (status === "error") { + _ref = _.keys(resp); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _results.push($("*[name=" + key + "]", $form).addClass("validationError")); + } + return _results; + } + }, this) + }); + } + } + }; + return UberView; + })(); +}).call(this); +}, "web-lib/views/footer": function(exports, require, module) {(function() { + var footerTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + footerTemplate = require('web-lib/templates/footer'); + exports.SharedFooterView = (function() { + __extends(SharedFooterView, Backbone.View); + function SharedFooterView() { + SharedFooterView.__super__.constructor.apply(this, arguments); + } + SharedFooterView.prototype.id = 'footer_view'; + SharedFooterView.prototype.events = { + 'click .language': 'intl_set_cookie_locale' + }; + SharedFooterView.prototype.render = function() { + $(this.el).html(footerTemplate()); + this.delegateEvents(); + return this; + }; + SharedFooterView.prototype.intl_set_cookie_locale = function(e) { + var _ref; + i18n.setLocale(e != null ? (_ref = e.srcElement) != null ? _ref.id : void 0 : void 0); + return location.reload(); + }; + return SharedFooterView; + })(); +}).call(this); +}}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/embed-tokens.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/embed-tokens.js new file mode 100755 index 00000000..61307eeb --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/embed-tokens.js @@ -0,0 +1,15 @@ +#! /usr/bin/env node + +global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util"); +var fs = require("fs"); +var uglify = require("uglify-js"), // symlink ~/.node_libraries/uglify-js.js to ../uglify-js.js + jsp = uglify.parser, + pro = uglify.uglify; + +var code = fs.readFileSync("embed-tokens.js", "utf8").replace(/^#.*$/mg, ""); +var ast = jsp.parse(code, null, true); + +// trololo +function fooBar() {} + +console.log(sys.inspect(ast, null, null)); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto.js new file mode 100644 index 00000000..945960c2 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto.js @@ -0,0 +1,26 @@ +function unique(arqw) { + var a = [], i, j + outer: for (i = 0; i < arqw.length; i++) { + for (j = 0; j < a.length; j++) { + if (a[j] == arqw[i]) { + continue outer + } + } + a[a.length] = arqw[i] + } + return a +} + + +function unique(arqw) { + var crap = [], i, j + outer: for (i = 0; i < arqw.length; i++) { + for (j = 0; j < crap.length; j++) { + if (crap[j] == arqw[i]) { + continue outer + } + } + crap[crap.length] = arqw[i] + } + return crap +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto2.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto2.js new file mode 100644 index 00000000..d13b2bc0 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto2.js @@ -0,0 +1,8 @@ +function q(qooo) { + var a; + foo: for(;;) { + a++; + if (something) break foo; + return qooo; + } +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/hoist.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/hoist.js new file mode 100644 index 00000000..4bf2b94d --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/hoist.js @@ -0,0 +1,33 @@ +function foo(arg1, arg2, arg3, arg4, arg5, arg6) { + var a = 5; + { + var d = 10, mak = 20, buz = 30; + var q = buz * 2; + } + if (moo) { + var a, b, c; + } + for (var arg1 = 0, d = 20; arg1 < 10; ++arg1) + console.log(arg3); + for (var i in mak) {} + for (j in d) {} + var d; + + function test() { + + }; + + //test(); + + (function moo(first, second){ + console.log(first); + })(1); + + (function moo(first, second){ + console.log(moo()); + })(1); +} + + +var foo; +var bar; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument.js new file mode 100644 index 00000000..c6a9d798 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument.js @@ -0,0 +1,97 @@ +// sample on how to use the parser and walker API to instrument some code + +var jsp = require("uglify-js").parser; +var pro = require("uglify-js").uglify; + +function instrument(code) { + var ast = jsp.parse(code, false, true); // true for the third arg specifies that we want + // to have start/end tokens embedded in the + // statements + var w = pro.ast_walker(); + + // we're gonna need this to push elements that we're currently looking at, to avoid + // endless recursion. + var analyzing = []; + function do_stat() { + var ret; + if (this[0].start && analyzing.indexOf(this) < 0) { + // without the `analyzing' hack, w.walk(this) would re-enter here leading + // to infinite recursion + analyzing.push(this); + ret = [ "splice", // XXX: "block" is safer + [ [ "stat", + [ "call", [ "name", "trace" ], + [ [ "string", this[0].toString() ], + [ "num", this[0].start.line ], + [ "num", this[0].start.col ], + [ "num", this[0].end.line ], + [ "num", this[0].end.col ]]]], + w.walk(this) ]]; + analyzing.pop(this); + } + return ret; + }; + var new_ast = w.with_walkers({ + "stat" : do_stat, + "label" : do_stat, + "break" : do_stat, + "continue" : do_stat, + "debugger" : do_stat, + "var" : do_stat, + "const" : do_stat, + "return" : do_stat, + "throw" : do_stat, + "try" : do_stat, + "defun" : do_stat, + "if" : do_stat, + "while" : do_stat, + "do" : do_stat, + "for" : do_stat, + "for-in" : do_stat, + "switch" : do_stat, + "with" : do_stat + }, function(){ + return w.walk(ast); + }); + return pro.gen_code(new_ast, { beautify: true }); +} + + + + +////// test code follows. + +var code = instrument(test.toString()); +console.log(code); + +function test() { + // simple stats + a = 5; + c += a + b; + "foo"; + + // var + var foo = 5; + const bar = 6, baz = 7; + + // switch block. note we can't track case lines the same way. + switch ("foo") { + case "foo": + return 1; + case "bar": + return 2; + } + + // for/for in + for (var i = 0; i < 5; ++i) { + console.log("Hello " + i); + } + for (var i in [ 1, 2, 3]) { + console.log(i); + } + + // note however that the following is broken. I guess we + // should add the block brackets in this case... + for (var i = 0; i < 5; ++i) + console.log("foo"); +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument2.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument2.js new file mode 100644 index 00000000..6aee5f3f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument2.js @@ -0,0 +1,138 @@ +// sample on how to use the parser and walker API to instrument some code + +var jsp = require("uglify-js").parser; +var pro = require("uglify-js").uglify; + +function instrument(code) { + var ast = jsp.parse(code, false, true); // true for the third arg specifies that we want + // to have start/end tokens embedded in the + // statements + var w = pro.ast_walker(); + + function trace (line, comment) { + var code = pro.gen_code(line, { beautify: true }); + var data = line[0] + + var args = [] + if (!comment) comment = "" + if (typeof data === "object") { + code = code.split(/\n/).shift() + args = [ [ "string", data.toString() ], + [ "string", code ], + [ "num", data.start.line ], + [ "num", data.start.col ], + [ "num", data.end.line ], + [ "num", data.end.col ]] + } else { + args = [ [ "string", data ], + [ "string", code ]] + + } + return [ "call", [ "name", "trace" ], args ]; + } + + // we're gonna need this to push elements that we're currently looking at, to avoid + // endless recursion. + var analyzing = []; + function do_stat() { + var ret; + if (this[0].start && analyzing.indexOf(this) < 0) { + // without the `analyzing' hack, w.walk(this) would re-enter here leading + // to infinite recursion + analyzing.push(this); + ret = [ "splice", + [ [ "stat", trace(this) ], + w.walk(this) ]]; + analyzing.pop(this); + } + return ret; + } + + function do_cond(c, t, f) { + return [ this[0], w.walk(c), + ["seq", trace(t), w.walk(t) ], + ["seq", trace(f), w.walk(f) ]]; + } + + function do_binary(c, l, r) { + if (c !== "&&" && c !== "||") { + return [this[0], c, w.walk(l), w.walk(r)]; + } + return [ this[0], c, + ["seq", trace(l), w.walk(l) ], + ["seq", trace(r), w.walk(r) ]]; + } + + var new_ast = w.with_walkers({ + "stat" : do_stat, + "label" : do_stat, + "break" : do_stat, + "continue" : do_stat, + "debugger" : do_stat, + "var" : do_stat, + "const" : do_stat, + "return" : do_stat, + "throw" : do_stat, + "try" : do_stat, + "defun" : do_stat, + "if" : do_stat, + "while" : do_stat, + "do" : do_stat, + "for" : do_stat, + "for-in" : do_stat, + "switch" : do_stat, + "with" : do_stat, + "conditional" : do_cond, + "binary" : do_binary + }, function(){ + return w.walk(ast); + }); + return pro.gen_code(new_ast, { beautify: true }); +} + + +////// test code follows. + +var code = instrument(test.toString()); +console.log(code); + +function test() { + // simple stats + a = 5; + c += a + b; + "foo"; + + // var + var foo = 5; + const bar = 6, baz = 7; + + // switch block. note we can't track case lines the same way. + switch ("foo") { + case "foo": + return 1; + case "bar": + return 2; + } + + // for/for in + for (var i = 0; i < 5; ++i) { + console.log("Hello " + i); + } + for (var i in [ 1, 2, 3]) { + console.log(i); + } + + for (var i = 0; i < 5; ++i) + console.log("foo"); + + for (var i = 0; i < 5; ++i) { + console.log("foo"); + } + + var k = plurp() ? 1 : 0; + var x = a ? doX(y) && goZoo("zoo") + : b ? blerg({ x: y }) + : null; + + var x = X || Y; +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/liftvars.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/liftvars.js new file mode 100644 index 00000000..2f4b7fe2 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/liftvars.js @@ -0,0 +1,8 @@ +var UNUSED_VAR1 = 19; + +function main() { + var unused_var2 = 20; + alert(100); +} + +main(); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/test.js new file mode 100755 index 00000000..f295fba8 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/test.js @@ -0,0 +1,30 @@ +#! /usr/bin/env node + +global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util"); +var fs = require("fs"); +var uglify = require("uglify-js"), // symlink ~/.node_libraries/uglify-js.js to ../uglify-js.js + jsp = uglify.parser, + pro = uglify.uglify; + +var code = fs.readFileSync("hoist.js", "utf8"); +var ast = jsp.parse(code); + +ast = pro.ast_lift_variables(ast); + +var w = pro.ast_walker(); +ast = w.with_walkers({ + "function": function() { + var node = w.dive(this); // walk depth first + console.log(pro.gen_code(node, { beautify: true })); + return node; + }, + "name": function(name) { + return [ this[0], "X" ]; + } +}, function(){ + return w.walk(ast); +}); + +console.log(pro.gen_code(ast, { + beautify: true +})); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs.js new file mode 100644 index 00000000..0d5b7e0e --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs.js @@ -0,0 +1,3930 @@ +/** + * @fileoverview + * + * JsWorld + * + *

Javascript library for localised formatting and parsing of: + *

    + *
  • Numbers + *
  • Dates and times + *
  • Currency + *
+ * + *

The library classes are configured with standard POSIX locale definitions + * derived from Unicode's Common Locale Data Repository (CLDR). + * + *

Website: JsWorld + * + * @author Vladimir Dzhuvinov + * @version 2.5 (2011-12-23) + */ + + + +/** + * @namespace Namespace container for the JsWorld library objects. + */ +jsworld = {}; + + +/** + * @function + * + * @description Formats a JavaScript Date object as an ISO-8601 date/time + * string. + * + * @param {Date} [d] A valid JavaScript Date object. If undefined the + * current date/time will be used. + * @param {Boolean} [withTZ] Include timezone offset, default false. + * + * @returns {String} The date/time formatted as YYYY-MM-DD HH:MM:SS. + */ +jsworld.formatIsoDateTime = function(d, withTZ) { + + if (typeof d === "undefined") + d = new Date(); // now + + if (typeof withTZ === "undefined") + withTZ = false; + + var s = jsworld.formatIsoDate(d) + " " + jsworld.formatIsoTime(d); + + if (withTZ) { + + var diff = d.getHours() - d.getUTCHours(); + var hourDiff = Math.abs(diff); + + var minuteUTC = d.getUTCMinutes(); + var minute = d.getMinutes(); + + if (minute != minuteUTC && minuteUTC < 30 && diff < 0) + hourDiff--; + + if (minute != minuteUTC && minuteUTC > 30 && diff > 0) + hourDiff--; + + var minuteDiff; + if (minute != minuteUTC) + minuteDiff = ":30"; + else + minuteDiff = ":00"; + + var timezone; + if (hourDiff < 10) + timezone = "0" + hourDiff + minuteDiff; + + else + timezone = "" + hourDiff + minuteDiff; + + if (diff < 0) + timezone = "-" + timezone; + + else + timezone = "+" + timezone; + + s = s + timezone; + } + + return s; +}; + + +/** + * @function + * + * @description Formats a JavaScript Date object as an ISO-8601 date string. + * + * @param {Date} [d] A valid JavaScript Date object. If undefined the current + * date will be used. + * + * @returns {String} The date formatted as YYYY-MM-DD. + */ +jsworld.formatIsoDate = function(d) { + + if (typeof d === "undefined") + d = new Date(); // now + + var year = d.getFullYear(); + var month = d.getMonth() + 1; + var day = d.getDate(); + + return year + "-" + jsworld._zeroPad(month, 2) + "-" + jsworld._zeroPad(day, 2); +}; + + +/** + * @function + * + * @description Formats a JavaScript Date object as an ISO-8601 time string. + * + * @param {Date} [d] A valid JavaScript Date object. If undefined the current + * time will be used. + * + * @returns {String} The time formatted as HH:MM:SS. + */ +jsworld.formatIsoTime = function(d) { + + if (typeof d === "undefined") + d = new Date(); // now + + var hour = d.getHours(); + var minute = d.getMinutes(); + var second = d.getSeconds(); + + return jsworld._zeroPad(hour, 2) + ":" + jsworld._zeroPad(minute, 2) + ":" + jsworld._zeroPad(second, 2); +}; + + +/** + * @function + * + * @description Parses an ISO-8601 formatted date/time string to a JavaScript + * Date object. + * + * @param {String} isoDateTimeVal An ISO-8601 formatted date/time string. + * + *

Accepted formats: + * + *

    + *
  • YYYY-MM-DD HH:MM:SS + *
  • YYYYMMDD HHMMSS + *
  • YYYY-MM-DD HHMMSS + *
  • YYYYMMDD HH:MM:SS + *
+ * + * @returns {Date} The corresponding Date object. + * + * @throws Error on a badly formatted date/time string or on a invalid date. + */ +jsworld.parseIsoDateTime = function(isoDateTimeVal) { + + if (typeof isoDateTimeVal != "string") + throw "Error: The parameter must be a string"; + + // First, try to match "YYYY-MM-DD HH:MM:SS" format + var matches = isoDateTimeVal.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d)/); + + // If unsuccessful, try to match "YYYYMMDD HHMMSS" format + if (matches === null) + matches = isoDateTimeVal.match(/^(\d\d\d\d)(\d\d)(\d\d)[T ](\d\d)(\d\d)(\d\d)/); + + // ... try to match "YYYY-MM-DD HHMMSS" format + if (matches === null) + matches = isoDateTimeVal.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d)(\d\d)(\d\d)/); + + // ... try to match "YYYYMMDD HH:MM:SS" format + if (matches === null) + matches = isoDateTimeVal.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d)/); + + // Report bad date/time string + if (matches === null) + throw "Error: Invalid ISO-8601 date/time string"; + + // Force base 10 parse int as some values may have leading zeros! + // (to avoid implicit octal base conversion) + var year = parseInt(matches[1], 10); + var month = parseInt(matches[2], 10); + var day = parseInt(matches[3], 10); + + var hour = parseInt(matches[4], 10); + var mins = parseInt(matches[5], 10); + var secs = parseInt(matches[6], 10); + + // Simple value range check, leap years not checked + // Note: the originial ISO time spec for leap hours (24:00:00) and seconds (00:00:60) is not supported + if (month < 1 || month > 12 || + day < 1 || day > 31 || + hour < 0 || hour > 23 || + mins < 0 || mins > 59 || + secs < 0 || secs > 59 ) + + throw "Error: Invalid ISO-8601 date/time value"; + + var d = new Date(year, month - 1, day, hour, mins, secs); + + // Check if the input date was valid + // (JS Date does automatic forward correction) + if (d.getDate() != day || d.getMonth() +1 != month) + throw "Error: Invalid date"; + + return d; +}; + + +/** + * @function + * + * @description Parses an ISO-8601 formatted date string to a JavaScript + * Date object. + * + * @param {String} isoDateVal An ISO-8601 formatted date string. + * + *

Accepted formats: + * + *

    + *
  • YYYY-MM-DD + *
  • YYYYMMDD + *
+ * + * @returns {Date} The corresponding Date object. + * + * @throws Error on a badly formatted date string or on a invalid date. + */ +jsworld.parseIsoDate = function(isoDateVal) { + + if (typeof isoDateVal != "string") + throw "Error: The parameter must be a string"; + + // First, try to match "YYYY-MM-DD" format + var matches = isoDateVal.match(/^(\d\d\d\d)-(\d\d)-(\d\d)/); + + // If unsuccessful, try to match "YYYYMMDD" format + if (matches === null) + matches = isoDateVal.match(/^(\d\d\d\d)(\d\d)(\d\d)/); + + // Report bad date/time string + if (matches === null) + throw "Error: Invalid ISO-8601 date string"; + + // Force base 10 parse int as some values may have leading zeros! + // (to avoid implicit octal base conversion) + var year = parseInt(matches[1], 10); + var month = parseInt(matches[2], 10); + var day = parseInt(matches[3], 10); + + // Simple value range check, leap years not checked + if (month < 1 || month > 12 || + day < 1 || day > 31 ) + + throw "Error: Invalid ISO-8601 date value"; + + var d = new Date(year, month - 1, day); + + // Check if the input date was valid + // (JS Date does automatic forward correction) + if (d.getDate() != day || d.getMonth() +1 != month) + throw "Error: Invalid date"; + + return d; +}; + + +/** + * @function + * + * @description Parses an ISO-8601 formatted time string to a JavaScript + * Date object. + * + * @param {String} isoTimeVal An ISO-8601 formatted time string. + * + *

Accepted formats: + * + *

    + *
  • HH:MM:SS + *
  • HHMMSS + *
+ * + * @returns {Date} The corresponding Date object, with year, month and day set + * to zero. + * + * @throws Error on a badly formatted time string. + */ +jsworld.parseIsoTime = function(isoTimeVal) { + + if (typeof isoTimeVal != "string") + throw "Error: The parameter must be a string"; + + // First, try to match "HH:MM:SS" format + var matches = isoTimeVal.match(/^(\d\d):(\d\d):(\d\d)/); + + // If unsuccessful, try to match "HHMMSS" format + if (matches === null) + matches = isoTimeVal.match(/^(\d\d)(\d\d)(\d\d)/); + + // Report bad date/time string + if (matches === null) + throw "Error: Invalid ISO-8601 date/time string"; + + // Force base 10 parse int as some values may have leading zeros! + // (to avoid implicit octal base conversion) + var hour = parseInt(matches[1], 10); + var mins = parseInt(matches[2], 10); + var secs = parseInt(matches[3], 10); + + // Simple value range check, leap years not checked + if (hour < 0 || hour > 23 || + mins < 0 || mins > 59 || + secs < 0 || secs > 59 ) + + throw "Error: Invalid ISO-8601 time value"; + + return new Date(0, 0, 0, hour, mins, secs); +}; + + +/** + * @private + * + * @description Trims leading and trailing whitespace from a string. + * + *

Used non-regexp the method from http://blog.stevenlevithan.com/archives/faster-trim-javascript + * + * @param {String} str The string to trim. + * + * @returns {String} The trimmed string. + */ +jsworld._trim = function(str) { + + var whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000'; + + for (var i = 0; i < str.length; i++) { + + if (whitespace.indexOf(str.charAt(i)) === -1) { + str = str.substring(i); + break; + } + } + + for (i = str.length - 1; i >= 0; i--) { + if (whitespace.indexOf(str.charAt(i)) === -1) { + str = str.substring(0, i + 1); + break; + } + } + + return whitespace.indexOf(str.charAt(0)) === -1 ? str : ''; +}; + + + +/** + * @private + * + * @description Returns true if the argument represents a decimal number. + * + * @param {Number|String} arg The argument to test. + * + * @returns {Boolean} true if the argument represents a decimal number, + * otherwise false. + */ +jsworld._isNumber = function(arg) { + + if (typeof arg == "number") + return true; + + if (typeof arg != "string") + return false; + + // ensure string + var s = arg + ""; + + return (/^-?(\d+|\d*\.\d+)$/).test(s); +}; + + +/** + * @private + * + * @description Returns true if the argument represents a decimal integer. + * + * @param {Number|String} arg The argument to test. + * + * @returns {Boolean} true if the argument represents an integer, otherwise + * false. + */ +jsworld._isInteger = function(arg) { + + if (typeof arg != "number" && typeof arg != "string") + return false; + + // convert to string + var s = arg + ""; + + return (/^-?\d+$/).test(s); +}; + + +/** + * @private + * + * @description Returns true if the argument represents a decimal float. + * + * @param {Number|String} arg The argument to test. + * + * @returns {Boolean} true if the argument represents a float, otherwise false. + */ +jsworld._isFloat = function(arg) { + + if (typeof arg != "number" && typeof arg != "string") + return false; + + // convert to string + var s = arg + ""; + + return (/^-?\.\d+?$/).test(s); +}; + + +/** + * @private + * + * @description Checks if the specified formatting option is contained + * within the options string. + * + * @param {String} option The option to search for. + * @param {String} optionsString The options string. + * + * @returns {Boolean} true if the flag is found, else false + */ +jsworld._hasOption = function(option, optionsString) { + + if (typeof option != "string" || typeof optionsString != "string") + return false; + + if (optionsString.indexOf(option) != -1) + return true; + else + return false; +}; + + +/** + * @private + * + * @description String replacement function. + * + * @param {String} s The string to work on. + * @param {String} target The string to search for. + * @param {String} replacement The replacement. + * + * @returns {String} The new string. + */ +jsworld._stringReplaceAll = function(s, target, replacement) { + + var out; + + if (target.length == 1 && replacement.length == 1) { + // simple char/char case somewhat faster + out = ""; + + for (var i = 0; i < s.length; i++) { + + if (s.charAt(i) == target.charAt(0)) + out = out + replacement.charAt(0); + else + out = out + s.charAt(i); + } + + return out; + } + else { + // longer target and replacement strings + out = s; + + var index = out.indexOf(target); + + while (index != -1) { + + out = out.replace(target, replacement); + + index = out.indexOf(target); + } + + return out; + } +}; + + +/** + * @private + * + * @description Tests if a string starts with the specified substring. + * + * @param {String} testedString The string to test. + * @param {String} sub The string to match. + * + * @returns {Boolean} true if the test succeeds. + */ +jsworld._stringStartsWith = function (testedString, sub) { + + if (testedString.length < sub.length) + return false; + + for (var i = 0; i < sub.length; i++) { + if (testedString.charAt(i) != sub.charAt(i)) + return false; + } + + return true; +}; + + +/** + * @private + * + * @description Gets the requested precision from an options string. + * + *

Example: ".3" returns 3 decimal places precision. + * + * @param {String} optionsString The options string. + * + * @returns {integer Number} The requested precision, -1 if not specified. + */ +jsworld._getPrecision = function (optionsString) { + + if (typeof optionsString != "string") + return -1; + + var m = optionsString.match(/\.(\d)/); + if (m) + return parseInt(m[1], 10); + else + return -1; +}; + + +/** + * @private + * + * @description Takes a decimal numeric amount (optionally as string) and + * returns its integer and fractional parts packed into an object. + * + * @param {Number|String} amount The amount, e.g. "123.45" or "-56.78" + * + * @returns {object} Parsed amount object with properties: + * {String} integer : the integer part + * {String} fraction : the fraction part + */ +jsworld._splitNumber = function (amount) { + + if (typeof amount == "number") + amount = amount + ""; + + var obj = {}; + + // remove negative sign + if (amount.charAt(0) == "-") + amount = amount.substring(1); + + // split amount into integer and decimal parts + var amountParts = amount.split("."); + if (!amountParts[1]) + amountParts[1] = ""; // we need "" instead of null + + obj.integer = amountParts[0]; + obj.fraction = amountParts[1]; + + return obj; +}; + + +/** + * @private + * + * @description Formats the integer part using the specified grouping + * and thousands separator. + * + * @param {String} intPart The integer part of the amount, as string. + * @param {String} grouping The grouping definition. + * @param {String} thousandsSep The thousands separator. + * + * @returns {String} The formatted integer part. + */ +jsworld._formatIntegerPart = function (intPart, grouping, thousandsSep) { + + // empty separator string? no grouping? + // -> return immediately with no formatting! + if (thousandsSep == "" || grouping == "-1") + return intPart; + + // turn the semicolon-separated string of integers into an array + var groupSizes = grouping.split(";"); + + // the formatted output string + var out = ""; + + // the intPart string position to process next, + // start at string end, e.g. "10000000 0) { + + // get next group size (if any, otherwise keep last) + if (groupSizes.length > 0) + size = parseInt(groupSizes.shift(), 10); + + // int parse error? + if (isNaN(size)) + throw "Error: Invalid grouping"; + + // size is -1? -> no more grouping, so just copy string remainder + if (size == -1) { + out = intPart.substring(0, pos) + out; + break; + } + + pos -= size; // move to next sep. char. position + + // position underrun? -> just copy string remainder + if (pos < 1) { + out = intPart.substring(0, pos + size) + out; + break; + } + + // extract group and apply sep. char. + out = thousandsSep + intPart.substring(pos, pos + size) + out; + } + + return out; +}; + + +/** + * @private + * + * @description Formats the fractional part to the specified decimal + * precision. + * + * @param {String} fracPart The fractional part of the amount + * @param {integer Number} precision The desired decimal precision + * + * @returns {String} The formatted fractional part. + */ +jsworld._formatFractionPart = function (fracPart, precision) { + + // append zeroes up to precision if necessary + for (var i=0; fracPart.length < precision; i++) + fracPart = fracPart + "0"; + + return fracPart; +}; + + +/** + * @private + * + * @desription Converts a number to string and pad it with leading zeroes if the + * string is shorter than length. + * + * @param {integer Number} number The number value subjected to selective padding. + * @param {integer Number} length If the number has fewer digits than this length + * apply padding. + * + * @returns {String} The formatted string. + */ +jsworld._zeroPad = function(number, length) { + + // ensure string + var s = number + ""; + + while (s.length < length) + s = "0" + s; + + return s; +}; + + +/** + * @private + * @description Converts a number to string and pads it with leading spaces if + * the string is shorter than length. + * + * @param {integer Number} number The number value subjected to selective padding. + * @param {integer Number} length If the number has fewer digits than this length + * apply padding. + * + * @returns {String} The formatted string. + */ +jsworld._spacePad = function(number, length) { + + // ensure string + var s = number + ""; + + while (s.length < length) + s = " " + s; + + return s; +}; + + + +/** + * @class + * Represents a POSIX-style locale with its numeric, monetary and date/time + * properties. Also provides a set of locale helper methods. + * + *

The locale properties follow the POSIX standards: + * + *

+ * + * @public + * @constructor + * @description Creates a new locale object (POSIX-style) with the specified + * properties. + * + * @param {object} properties An object containing the raw locale properties: + * + * @param {String} properties.decimal_point + * + * A string containing the symbol that shall be used as the decimal + * delimiter (radix character) in numeric, non-monetary formatted + * quantities. This property cannot be omitted and cannot be set to the + * empty string. + * + * + * @param {String} properties.thousands_sep + * + * A string containing the symbol that shall be used as a separator for + * groups of digits to the left of the decimal delimiter in numeric, + * non-monetary formatted monetary quantities. + * + * + * @param {String} properties.grouping + * + * Defines the size of each group of digits in formatted non-monetary + * quantities. The operand is a sequence of integers separated by + * semicolons. Each integer specifies the number of digits in each group, + * with the initial integer defining the size of the group immediately + * preceding the decimal delimiter, and the following integers defining + * the preceding groups. If the last integer is not -1, then the size of + * the previous group (if any) shall be repeatedly used for the + * remainder of the digits. If the last integer is -1, then no further + * grouping shall be performed. + * + * + * @param {String} properties.int_curr_symbol + * + * The first three letters signify the ISO-4217 currency code, + * the fourth letter is the international symbol separation character + * (normally a space). + * + * + * @param {String} properties.currency_symbol + * + * The local shorthand currency symbol, e.g. "$" for the en_US locale + * + * + * @param {String} properties.mon_decimal_point + * + * The symbol to be used as the decimal delimiter (radix character) + * + * + * @param {String} properties.mon_thousands_sep + * + * The symbol to be used as a separator for groups of digits to the + * left of the decimal delimiter. + * + * + * @param {String} properties.mon_grouping + * + * A string that defines the size of each group of digits. The + * operand is a sequence of integers separated by semicolons (";"). + * Each integer specifies the number of digits in each group, with the + * initial integer defining the size of the group preceding the + * decimal delimiter, and the following integers defining the + * preceding groups. If the last integer is not -1, then the size of + * the previous group (if any) must be repeatedly used for the + * remainder of the digits. If the last integer is -1, then no + * further grouping is to be performed. + * + * + * @param {String} properties.positive_sign + * + * The string to indicate a non-negative monetary amount. + * + * + * @param {String} properties.negative_sign + * + * The string to indicate a negative monetary amount. + * + * + * @param {integer Number} properties.frac_digits + * + * An integer representing the number of fractional digits (those to + * the right of the decimal delimiter) to be written in a formatted + * monetary quantity using currency_symbol. + * + * + * @param {integer Number} properties.int_frac_digits + * + * An integer representing the number of fractional digits (those to + * the right of the decimal delimiter) to be written in a formatted + * monetary quantity using int_curr_symbol. + * + * + * @param {integer Number} properties.p_cs_precedes + * + * An integer set to 1 if the currency_symbol precedes the value for a + * monetary quantity with a non-negative value, and set to 0 if the + * symbol succeeds the value. + * + * + * @param {integer Number} properties.n_cs_precedes + * + * An integer set to 1 if the currency_symbol precedes the value for a + * monetary quantity with a negative value, and set to 0 if the symbol + * succeeds the value. + * + * + * @param {integer Number} properties.p_sep_by_space + * + * Set to a value indicating the separation of the currency_symbol, + * the sign string, and the value for a non-negative formatted monetary + * quantity: + * + *

0 No space separates the currency symbol and value.

+ * + *

1 If the currency symbol and sign string are adjacent, a space + * separates them from the value; otherwise, a space separates + * the currency symbol from the value.

+ * + *

2 If the currency symbol and sign string are adjacent, a space + * separates them; otherwise, a space separates the sign string + * from the value.

+ * + * + * @param {integer Number} properties.n_sep_by_space + * + * Set to a value indicating the separation of the currency_symbol, + * the sign string, and the value for a negative formatted monetary + * quantity. Rules same as for p_sep_by_space. + * + * + * @param {integer Number} properties.p_sign_posn + * + * An integer set to a value indicating the positioning of the + * positive_sign for a monetary quantity with a non-negative value: + * + *

0 Parentheses enclose the quantity and the currency_symbol.

+ * + *

1 The sign string precedes the quantity and the currency_symbol.

+ * + *

2 The sign string succeeds the quantity and the currency_symbol.

+ * + *

3 The sign string precedes the currency_symbol.

+ * + *

4 The sign string succeeds the currency_symbol.

+ * + * + * @param {integer Number} properties.n_sign_posn + * + * An integer set to a value indicating the positioning of the + * negative_sign for a negative formatted monetary quantity. Rules same + * as for p_sign_posn. + * + * + * @param {integer Number} properties.int_p_cs_precedes + * + * An integer set to 1 if the int_curr_symbol precedes the value for a + * monetary quantity with a non-negative value, and set to 0 if the + * symbol succeeds the value. + * + * + * @param {integer Number} properties.int_n_cs_precedes + * + * An integer set to 1 if the int_curr_symbol precedes the value for a + * monetary quantity with a negative value, and set to 0 if the symbol + * succeeds the value. + * + * + * @param {integer Number} properties.int_p_sep_by_space + * + * Set to a value indicating the separation of the int_curr_symbol, + * the sign string, and the value for a non-negative internationally + * formatted monetary quantity. Rules same as for p_sep_by_space. + * + * + * @param {integer Number} properties.int_n_sep_by_space + * + * Set to a value indicating the separation of the int_curr_symbol, + * the sign string, and the value for a negative internationally + * formatted monetary quantity. Rules same as for p_sep_by_space. + * + * + * @param {integer Number} properties.int_p_sign_posn + * + * An integer set to a value indicating the positioning of the + * positive_sign for a positive monetary quantity formatted with the + * international format. Rules same as for p_sign_posn. + * + * + * @param {integer Number} properties.int_n_sign_posn + * + * An integer set to a value indicating the positioning of the + * negative_sign for a negative monetary quantity formatted with the + * international format. Rules same as for p_sign_posn. + * + * + * @param {String[] | String} properties.abday + * + * The abbreviated weekday names, corresponding to the %a conversion + * specification. The property must be either an array of 7 strings or + * a string consisting of 7 semicolon-separated substrings, each + * surrounded by double-quotes. The first must be the abbreviated name + * of the day corresponding to Sunday, the second the abbreviated name + * of the day corresponding to Monday, and so on. + * + * + * @param {String[] | String} properties.day + * + * The full weekday names, corresponding to the %A conversion + * specification. The property must be either an array of 7 strings or + * a string consisting of 7 semicolon-separated substrings, each + * surrounded by double-quotes. The first must be the full name of the + * day corresponding to Sunday, the second the full name of the day + * corresponding to Monday, and so on. + * + * + * @param {String[] | String} properties.abmon + * + * The abbreviated month names, corresponding to the %b conversion + * specification. The property must be either an array of 12 strings or + * a string consisting of 12 semicolon-separated substrings, each + * surrounded by double-quotes. The first must be the abbreviated name + * of the first month of the year (January), the second the abbreviated + * name of the second month, and so on. + * + * + * @param {String[] | String} properties.mon + * + * The full month names, corresponding to the %B conversion + * specification. The property must be either an array of 12 strings or + * a string consisting of 12 semicolon-separated substrings, each + * surrounded by double-quotes. The first must be the full name of the + * first month of the year (January), the second the full name of the second + * month, and so on. + * + * + * @param {String} properties.d_fmt + * + * The appropriate date representation. The string may contain any + * combination of characters and conversion specifications (%). + * + * + * @param {String} properties.t_fmt + * + * The appropriate time representation. The string may contain any + * combination of characters and conversion specifications (%). + * + * + * @param {String} properties.d_t_fmt + * + * The appropriate date and time representation. The string may contain + * any combination of characters and conversion specifications (%). + * + * + * @param {String[] | String} properties.am_pm + * + * The appropriate representation of the ante-meridiem and post-meridiem + * strings, corresponding to the %p conversion specification. The property + * must be either an array of 2 strings or a string consisting of 2 + * semicolon-separated substrings, each surrounded by double-quotes. + * The first string must represent the ante-meridiem designation, the + * last string the post-meridiem designation. + * + * + * @throws @throws Error on a undefined or invalid locale property. + */ +jsworld.Locale = function(properties) { + + + /** + * @private + * + * @description Identifies the class for internal library purposes. + */ + this._className = "jsworld.Locale"; + + + /** + * @private + * + * @description Parses a day or month name definition list, which + * could be a ready JS array, e.g. ["Mon", "Tue", "Wed"...] or + * it could be a string formatted according to the classic POSIX + * definition e.g. "Mon";"Tue";"Wed";... + * + * @param {String[] | String} namesAn array or string defining + * the week/month names. + * @param {integer Number} expectedItems The number of expected list + * items, e.g. 7 for weekdays, 12 for months. + * + * @returns {String[]} The parsed (and checked) items. + * + * @throws Error on missing definition, unexpected item count or + * missing double-quotes. + */ + this._parseList = function(names, expectedItems) { + + var array = []; + + if (names == null) { + throw "Names not defined"; + } + else if (typeof names == "object") { + // we got a ready array + array = names; + } + else if (typeof names == "string") { + // we got the names in the classic POSIX form, do parse + array = names.split(";", expectedItems); + + for (var i = 0; i < array.length; i++) { + // check for and strip double quotes + if (array[i][0] == "\"" && array[i][array[i].length - 1] == "\"") + array[i] = array[i].slice(1, -1); + else + throw "Missing double quotes"; + } + } + else { + throw "Names must be an array or a string"; + } + + if (array.length != expectedItems) + throw "Expected " + expectedItems + " items, got " + array.length; + + return array; + }; + + + /** + * @private + * + * @description Validates a date/time format string, such as "H:%M:%S". + * Checks that the argument is of type "string" and is not empty. + * + * @param {String} formatString The format string. + * + * @returns {String} The validated string. + * + * @throws Error on null or empty string. + */ + this._validateFormatString = function(formatString) { + + if (typeof formatString == "string" && formatString.length > 0) + return formatString; + else + throw "Empty or no string"; + }; + + + // LC_NUMERIC + + if (properties == null || typeof properties != "object") + throw "Error: Invalid/missing locale properties"; + + + if (typeof properties.decimal_point != "string") + throw "Error: Invalid/missing decimal_point property"; + + this.decimal_point = properties.decimal_point; + + + if (typeof properties.thousands_sep != "string") + throw "Error: Invalid/missing thousands_sep property"; + + this.thousands_sep = properties.thousands_sep; + + + if (typeof properties.grouping != "string") + throw "Error: Invalid/missing grouping property"; + + this.grouping = properties.grouping; + + + // LC_MONETARY + + if (typeof properties.int_curr_symbol != "string") + throw "Error: Invalid/missing int_curr_symbol property"; + + if (! /[A-Za-z]{3}.?/.test(properties.int_curr_symbol)) + throw "Error: Invalid int_curr_symbol property"; + + this.int_curr_symbol = properties.int_curr_symbol; + + + if (typeof properties.currency_symbol != "string") + throw "Error: Invalid/missing currency_symbol property"; + + this.currency_symbol = properties.currency_symbol; + + + if (typeof properties.frac_digits != "number" && properties.frac_digits < 0) + throw "Error: Invalid/missing frac_digits property"; + + this.frac_digits = properties.frac_digits; + + + // may be empty string/null for currencies with no fractional part + if (properties.mon_decimal_point === null || properties.mon_decimal_point == "") { + + if (this.frac_digits > 0) + throw "Error: Undefined mon_decimal_point property"; + else + properties.mon_decimal_point = ""; + } + + if (typeof properties.mon_decimal_point != "string") + throw "Error: Invalid/missing mon_decimal_point property"; + + this.mon_decimal_point = properties.mon_decimal_point; + + + if (typeof properties.mon_thousands_sep != "string") + throw "Error: Invalid/missing mon_thousands_sep property"; + + this.mon_thousands_sep = properties.mon_thousands_sep; + + + if (typeof properties.mon_grouping != "string") + throw "Error: Invalid/missing mon_grouping property"; + + this.mon_grouping = properties.mon_grouping; + + + if (typeof properties.positive_sign != "string") + throw "Error: Invalid/missing positive_sign property"; + + this.positive_sign = properties.positive_sign; + + + if (typeof properties.negative_sign != "string") + throw "Error: Invalid/missing negative_sign property"; + + this.negative_sign = properties.negative_sign; + + + + if (properties.p_cs_precedes !== 0 && properties.p_cs_precedes !== 1) + throw "Error: Invalid/missing p_cs_precedes property, must be 0 or 1"; + + this.p_cs_precedes = properties.p_cs_precedes; + + + if (properties.n_cs_precedes !== 0 && properties.n_cs_precedes !== 1) + throw "Error: Invalid/missing n_cs_precedes, must be 0 or 1"; + + this.n_cs_precedes = properties.n_cs_precedes; + + + if (properties.p_sep_by_space !== 0 && + properties.p_sep_by_space !== 1 && + properties.p_sep_by_space !== 2) + throw "Error: Invalid/missing p_sep_by_space property, must be 0, 1 or 2"; + + this.p_sep_by_space = properties.p_sep_by_space; + + + if (properties.n_sep_by_space !== 0 && + properties.n_sep_by_space !== 1 && + properties.n_sep_by_space !== 2) + throw "Error: Invalid/missing n_sep_by_space property, must be 0, 1, or 2"; + + this.n_sep_by_space = properties.n_sep_by_space; + + + if (properties.p_sign_posn !== 0 && + properties.p_sign_posn !== 1 && + properties.p_sign_posn !== 2 && + properties.p_sign_posn !== 3 && + properties.p_sign_posn !== 4) + throw "Error: Invalid/missing p_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.p_sign_posn = properties.p_sign_posn; + + + if (properties.n_sign_posn !== 0 && + properties.n_sign_posn !== 1 && + properties.n_sign_posn !== 2 && + properties.n_sign_posn !== 3 && + properties.n_sign_posn !== 4) + throw "Error: Invalid/missing n_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.n_sign_posn = properties.n_sign_posn; + + + if (typeof properties.int_frac_digits != "number" && properties.int_frac_digits < 0) + throw "Error: Invalid/missing int_frac_digits property"; + + this.int_frac_digits = properties.int_frac_digits; + + + if (properties.int_p_cs_precedes !== 0 && properties.int_p_cs_precedes !== 1) + throw "Error: Invalid/missing int_p_cs_precedes property, must be 0 or 1"; + + this.int_p_cs_precedes = properties.int_p_cs_precedes; + + + if (properties.int_n_cs_precedes !== 0 && properties.int_n_cs_precedes !== 1) + throw "Error: Invalid/missing int_n_cs_precedes property, must be 0 or 1"; + + this.int_n_cs_precedes = properties.int_n_cs_precedes; + + + if (properties.int_p_sep_by_space !== 0 && + properties.int_p_sep_by_space !== 1 && + properties.int_p_sep_by_space !== 2) + throw "Error: Invalid/missing int_p_sep_by_spacev, must be 0, 1 or 2"; + + this.int_p_sep_by_space = properties.int_p_sep_by_space; + + + if (properties.int_n_sep_by_space !== 0 && + properties.int_n_sep_by_space !== 1 && + properties.int_n_sep_by_space !== 2) + throw "Error: Invalid/missing int_n_sep_by_space property, must be 0, 1, or 2"; + + this.int_n_sep_by_space = properties.int_n_sep_by_space; + + + if (properties.int_p_sign_posn !== 0 && + properties.int_p_sign_posn !== 1 && + properties.int_p_sign_posn !== 2 && + properties.int_p_sign_posn !== 3 && + properties.int_p_sign_posn !== 4) + throw "Error: Invalid/missing int_p_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.int_p_sign_posn = properties.int_p_sign_posn; + + + if (properties.int_n_sign_posn !== 0 && + properties.int_n_sign_posn !== 1 && + properties.int_n_sign_posn !== 2 && + properties.int_n_sign_posn !== 3 && + properties.int_n_sign_posn !== 4) + throw "Error: Invalid/missing int_n_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.int_n_sign_posn = properties.int_n_sign_posn; + + + // LC_TIME + + if (properties == null || typeof properties != "object") + throw "Error: Invalid/missing time locale properties"; + + + // parse the supported POSIX LC_TIME properties + + // abday + try { + this.abday = this._parseList(properties.abday, 7); + } + catch (error) { + throw "Error: Invalid abday property: " + error; + } + + // day + try { + this.day = this._parseList(properties.day, 7); + } + catch (error) { + throw "Error: Invalid day property: " + error; + } + + // abmon + try { + this.abmon = this._parseList(properties.abmon, 12); + } catch (error) { + throw "Error: Invalid abmon property: " + error; + } + + // mon + try { + this.mon = this._parseList(properties.mon, 12); + } catch (error) { + throw "Error: Invalid mon property: " + error; + } + + // d_fmt + try { + this.d_fmt = this._validateFormatString(properties.d_fmt); + } catch (error) { + throw "Error: Invalid d_fmt property: " + error; + } + + // t_fmt + try { + this.t_fmt = this._validateFormatString(properties.t_fmt); + } catch (error) { + throw "Error: Invalid t_fmt property: " + error; + } + + // d_t_fmt + try { + this.d_t_fmt = this._validateFormatString(properties.d_t_fmt); + } catch (error) { + throw "Error: Invalid d_t_fmt property: " + error; + } + + // am_pm + try { + var am_pm_strings = this._parseList(properties.am_pm, 2); + this.am = am_pm_strings[0]; + this.pm = am_pm_strings[1]; + } catch (error) { + // ignore empty/null string errors + this.am = ""; + this.pm = ""; + } + + + /** + * @public + * + * @description Returns the abbreviated name of the specified weekday. + * + * @param {integer Number} [weekdayNum] An integer between 0 and 6. Zero + * corresponds to Sunday, one to Monday, etc. If omitted the + * method will return an array of all abbreviated weekday + * names. + * + * @returns {String | String[]} The abbreviated name of the specified weekday + * or an array of all abbreviated weekday names. + * + * @throws Error on invalid argument. + */ + this.getAbbreviatedWeekdayName = function(weekdayNum) { + + if (typeof weekdayNum == "undefined" || weekdayNum === null) + return this.abday; + + if (! jsworld._isInteger(weekdayNum) || weekdayNum < 0 || weekdayNum > 6) + throw "Error: Invalid weekday argument, must be an integer [0..6]"; + + return this.abday[weekdayNum]; + }; + + + /** + * @public + * + * @description Returns the name of the specified weekday. + * + * @param {integer Number} [weekdayNum] An integer between 0 and 6. Zero + * corresponds to Sunday, one to Monday, etc. If omitted the + * method will return an array of all weekday names. + * + * @returns {String | String[]} The name of the specified weekday or an + * array of all weekday names. + * + * @throws Error on invalid argument. + */ + this.getWeekdayName = function(weekdayNum) { + + if (typeof weekdayNum == "undefined" || weekdayNum === null) + return this.day; + + if (! jsworld._isInteger(weekdayNum) || weekdayNum < 0 || weekdayNum > 6) + throw "Error: Invalid weekday argument, must be an integer [0..6]"; + + return this.day[weekdayNum]; + }; + + + /** + * @public + * + * @description Returns the abbreviated name of the specified month. + * + * @param {integer Number} [monthNum] An integer between 0 and 11. Zero + * corresponds to January, one to February, etc. If omitted the + * method will return an array of all abbreviated month names. + * + * @returns {String | String[]} The abbreviated name of the specified month + * or an array of all abbreviated month names. + * + * @throws Error on invalid argument. + */ + this.getAbbreviatedMonthName = function(monthNum) { + + if (typeof monthNum == "undefined" || monthNum === null) + return this.abmon; + + if (! jsworld._isInteger(monthNum) || monthNum < 0 || monthNum > 11) + throw "Error: Invalid month argument, must be an integer [0..11]"; + + return this.abmon[monthNum]; + }; + + + /** + * @public + * + * @description Returns the name of the specified month. + * + * @param {integer Number} [monthNum] An integer between 0 and 11. Zero + * corresponds to January, one to February, etc. If omitted the + * method will return an array of all month names. + * + * @returns {String | String[]} The name of the specified month or an array + * of all month names. + * + * @throws Error on invalid argument. + */ + this.getMonthName = function(monthNum) { + + if (typeof monthNum == "undefined" || monthNum === null) + return this.mon; + + if (! jsworld._isInteger(monthNum) || monthNum < 0 || monthNum > 11) + throw "Error: Invalid month argument, must be an integer [0..11]"; + + return this.mon[monthNum]; + }; + + + + /** + * @public + * + * @description Gets the decimal delimiter (radix) character for + * numeric quantities. + * + * @returns {String} The radix character. + */ + this.getDecimalPoint = function() { + + return this.decimal_point; + }; + + + /** + * @public + * + * @description Gets the local shorthand currency symbol. + * + * @returns {String} The currency symbol. + */ + this.getCurrencySymbol = function() { + + return this.currency_symbol; + }; + + + /** + * @public + * + * @description Gets the internaltion currency symbol (ISO-4217 code). + * + * @returns {String} The international currency symbol. + */ + this.getIntCurrencySymbol = function() { + + return this.int_curr_symbol.substring(0,3); + }; + + + /** + * @public + * + * @description Gets the position of the local (shorthand) currency + * symbol relative to the amount. Assumes a non-negative amount. + * + * @returns {Boolean} True if the symbol precedes the amount, false if + * the symbol succeeds the amount. + */ + this.currencySymbolPrecedes = function() { + + if (this.p_cs_precedes == 1) + return true; + else + return false; + }; + + + /** + * @public + * + * @description Gets the position of the international (ISO-4217 code) + * currency symbol relative to the amount. Assumes a non-negative + * amount. + * + * @returns {Boolean} True if the symbol precedes the amount, false if + * the symbol succeeds the amount. + */ + this.intCurrencySymbolPrecedes = function() { + + if (this.int_p_cs_precedes == 1) + return true; + else + return false; + + }; + + + /** + * @public + * + * @description Gets the decimal delimiter (radix) for monetary + * quantities. + * + * @returns {String} The radix character. + */ + this.getMonetaryDecimalPoint = function() { + + return this.mon_decimal_point; + }; + + + /** + * @public + * + * @description Gets the number of fractional digits for local + * (shorthand) symbol formatting. + * + * @returns {integer Number} The number of fractional digits. + */ + this.getFractionalDigits = function() { + + return this.frac_digits; + }; + + + /** + * @public + * + * @description Gets the number of fractional digits for + * international (ISO-4217 code) formatting. + * + * @returns {integer Number} The number of fractional digits. + */ + this.getIntFractionalDigits = function() { + + return this.int_frac_digits; + }; +}; + + + +/** + * @class + * Class for localised formatting of numbers. + * + *

See: + * POSIX LC_NUMERIC. + * + * + * @public + * @constructor + * @description Creates a new numeric formatter for the specified locale. + * + * @param {jsworld.Locale} locale A locale object specifying the required + * POSIX LC_NUMERIC formatting properties. + * + * @throws Error on constructor failure. + */ +jsworld.NumericFormatter = function(locale) { + + if (typeof locale != "object" || locale._className != "jsworld.Locale") + throw "Constructor error: You must provide a valid jsworld.Locale instance"; + + this.lc = locale; + + + /** + * @public + * + * @description Formats a decimal numeric value according to the preset + * locale. + * + * @param {Number|String} number The number to format. + * @param {String} [options] Options to modify the formatted output: + *

    + *
  • "^" suppress grouping + *
  • "+" force positive sign for positive amounts + *
  • "~" suppress positive/negative sign + *
  • ".n" specify decimal precision 'n' + *
+ * + * @returns {String} The formatted number. + * + * @throws "Error: Invalid input" on bad input. + */ + this.format = function(number, options) { + + if (typeof number == "string") + number = jsworld._trim(number); + + if (! jsworld._isNumber(number)) + throw "Error: The input is not a number"; + + var floatAmount = parseFloat(number, 10); + + // get the required precision + var reqPrecision = jsworld._getPrecision(options); + + // round to required precision + if (reqPrecision != -1) + floatAmount = Math.round(floatAmount * Math.pow(10, reqPrecision)) / Math.pow(10, reqPrecision); + + + // convert the float number to string and parse into + // object with properties integer and fraction + var parsedAmount = jsworld._splitNumber(String(floatAmount)); + + // format integer part with grouping chars + var formattedIntegerPart; + + if (floatAmount === 0) + formattedIntegerPart = "0"; + else + formattedIntegerPart = jsworld._hasOption("^", options) ? + parsedAmount.integer : + jsworld._formatIntegerPart(parsedAmount.integer, + this.lc.grouping, + this.lc.thousands_sep); + + // format the fractional part + var formattedFractionPart = + reqPrecision != -1 ? + jsworld._formatFractionPart(parsedAmount.fraction, reqPrecision) : + parsedAmount.fraction; + + + // join the integer and fraction parts using the decimal_point property + var formattedAmount = + formattedFractionPart.length ? + formattedIntegerPart + this.lc.decimal_point + formattedFractionPart : + formattedIntegerPart; + + // prepend sign? + if (jsworld._hasOption("~", options) || floatAmount === 0) { + // suppress both '+' and '-' signs, i.e. return abs value + return formattedAmount; + } + else { + if (jsworld._hasOption("+", options) || floatAmount < 0) { + if (floatAmount > 0) + // force '+' sign for positive amounts + return "+" + formattedAmount; + else if (floatAmount < 0) + // prepend '-' sign + return "-" + formattedAmount; + else + // zero case + return formattedAmount; + } + else { + // positive amount with no '+' sign + return formattedAmount; + } + } + }; +}; + + +/** + * @class + * Class for localised formatting of dates and times. + * + *

See: + * POSIX LC_TIME. + * + * @public + * @constructor + * @description Creates a new date/time formatter for the specified locale. + * + * @param {jsworld.Locale} locale A locale object specifying the required + * POSIX LC_TIME formatting properties. + * + * @throws Error on constructor failure. + */ +jsworld.DateTimeFormatter = function(locale) { + + + if (typeof locale != "object" || locale._className != "jsworld.Locale") + throw "Constructor error: You must provide a valid jsworld.Locale instance."; + + this.lc = locale; + + + /** + * @public + * + * @description Formats a date according to the preset locale. + * + * @param {Date|String} date A valid Date object instance or a string + * containing a valid ISO-8601 formatted date, e.g. "2010-31-03" + * or "2010-03-31 23:59:59". + * + * @returns {String} The formatted date + * + * @throws Error on invalid date argument + */ + this.formatDate = function(date) { + + var d = null; + + if (typeof date == "string") { + // assume ISO-8601 date string + try { + d = jsworld.parseIsoDate(date); + } catch (error) { + // try full ISO-8601 date/time string + d = jsworld.parseIsoDateTime(date); + } + } + else if (date !== null && typeof date == "object") { + // assume ready Date object + d = date; + } + else { + throw "Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"; + } + + return this._applyFormatting(d, this.lc.d_fmt); + }; + + + /** + * @public + * + * @description Formats a time according to the preset locale. + * + * @param {Date|String} date A valid Date object instance or a string + * containing a valid ISO-8601 formatted time, e.g. "23:59:59" + * or "2010-03-31 23:59:59". + * + * @returns {String} The formatted time. + * + * @throws Error on invalid date argument. + */ + this.formatTime = function(date) { + + var d = null; + + if (typeof date == "string") { + // assume ISO-8601 time string + try { + d = jsworld.parseIsoTime(date); + } catch (error) { + // try full ISO-8601 date/time string + d = jsworld.parseIsoDateTime(date); + } + } + else if (date !== null && typeof date == "object") { + // assume ready Date object + d = date; + } + else { + throw "Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"; + } + + return this._applyFormatting(d, this.lc.t_fmt); + }; + + + /** + * @public + * + * @description Formats a date/time value according to the preset + * locale. + * + * @param {Date|String} date A valid Date object instance or a string + * containing a valid ISO-8601 formatted date/time, e.g. + * "2010-03-31 23:59:59". + * + * @returns {String} The formatted time. + * + * @throws Error on invalid argument. + */ + this.formatDateTime = function(date) { + + var d = null; + + if (typeof date == "string") { + // assume ISO-8601 format + d = jsworld.parseIsoDateTime(date); + } + else if (date !== null && typeof date == "object") { + // assume ready Date object + d = date; + } + else { + throw "Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"; + } + + return this._applyFormatting(d, this.lc.d_t_fmt); + }; + + + /** + * @private + * + * @description Apples formatting to the Date object according to the + * format string. + * + * @param {Date} d A valid Date instance. + * @param {String} s The formatting string with '%' placeholders. + * + * @returns {String} The formatted string. + */ + this._applyFormatting = function(d, s) { + + s = s.replace(/%%/g, '%'); + s = s.replace(/%a/g, this.lc.abday[d.getDay()]); + s = s.replace(/%A/g, this.lc.day[d.getDay()]); + s = s.replace(/%b/g, this.lc.abmon[d.getMonth()]); + s = s.replace(/%B/g, this.lc.mon[d.getMonth()]); + s = s.replace(/%d/g, jsworld._zeroPad(d.getDate(), 2)); + s = s.replace(/%e/g, jsworld._spacePad(d.getDate(), 2)); + s = s.replace(/%F/g, d.getFullYear() + + "-" + + jsworld._zeroPad(d.getMonth()+1, 2) + + "-" + + jsworld._zeroPad(d.getDate(), 2)); + s = s.replace(/%h/g, this.lc.abmon[d.getMonth()]); // same as %b + s = s.replace(/%H/g, jsworld._zeroPad(d.getHours(), 2)); + s = s.replace(/%I/g, jsworld._zeroPad(this._hours12(d.getHours()), 2)); + s = s.replace(/%k/g, d.getHours()); + s = s.replace(/%l/g, this._hours12(d.getHours())); + s = s.replace(/%m/g, jsworld._zeroPad(d.getMonth()+1, 2)); + s = s.replace(/%n/g, "\n"); + s = s.replace(/%M/g, jsworld._zeroPad(d.getMinutes(), 2)); + s = s.replace(/%p/g, this._getAmPm(d.getHours())); + s = s.replace(/%P/g, this._getAmPm(d.getHours()).toLocaleLowerCase()); // safe? + s = s.replace(/%R/g, jsworld._zeroPad(d.getHours(), 2) + + ":" + + jsworld._zeroPad(d.getMinutes(), 2)); + s = s.replace(/%S/g, jsworld._zeroPad(d.getSeconds(), 2)); + s = s.replace(/%T/g, jsworld._zeroPad(d.getHours(), 2) + + ":" + + jsworld._zeroPad(d.getMinutes(), 2) + + ":" + + jsworld._zeroPad(d.getSeconds(), 2)); + s = s.replace(/%w/g, this.lc.day[d.getDay()]); + s = s.replace(/%y/g, new String(d.getFullYear()).substring(2)); + s = s.replace(/%Y/g, d.getFullYear()); + + s = s.replace(/%Z/g, ""); // to do: ignored until a reliable TMZ method found + + s = s.replace(/%[a-zA-Z]/g, ""); // ignore all other % sequences + + return s; + }; + + + /** + * @private + * + * @description Does 24 to 12 hour conversion. + * + * @param {integer Number} hour24 Hour [0..23]. + * + * @returns {integer Number} Corresponding hour [1..12]. + */ + this._hours12 = function(hour24) { + + if (hour24 === 0) + return 12; // 00h is 12AM + + else if (hour24 > 12) + return hour24 - 12; // 1PM to 11PM + + else + return hour24; // 1AM to 12PM + }; + + + /** + * @private + * + * @description Gets the appropriate localised AM or PM string depending + * on the day hour. Special cases: midnight is 12AM, noon is 12PM. + * + * @param {integer Number} hour24 Hour [0..23]. + * + * @returns {String} The corresponding localised AM or PM string. + */ + this._getAmPm = function(hour24) { + + if (hour24 < 12) + return this.lc.am; + else + return this.lc.pm; + }; +}; + + + +/** + * @class Class for localised formatting of currency amounts. + * + *

See: + * POSIX LC_MONETARY. + * + * @public + * @constructor + * @description Creates a new monetary formatter for the specified locale. + * + * @param {jsworld.Locale} locale A locale object specifying the required + * POSIX LC_MONETARY formatting properties. + * @param {String} [currencyCode] Set the currency explicitly by + * passing its international ISO-4217 code, e.g. "USD", "EUR", "GBP". + * Use this optional parameter to override the default local currency + * @param {String} [altIntSymbol] Non-local currencies are formatted + * with their international ISO-4217 code to prevent ambiguity. + * Use this optional argument to force a different symbol, such as the + * currency's shorthand sign. This is mostly useful when the shorthand + * sign is both internationally recognised and identifies the currency + * uniquely (e.g. the Euro sign). + * + * @throws Error on constructor failure. + */ +jsworld.MonetaryFormatter = function(locale, currencyCode, altIntSymbol) { + + if (typeof locale != "object" || locale._className != "jsworld.Locale") + throw "Constructor error: You must provide a valid jsworld.Locale instance"; + + this.lc = locale; + + /** + * @private + * @description Lookup table to determine the fraction digits for a + * specific currency; most currencies subdivide at 1/100 (2 fractional + * digits), so we store only those that deviate from the default. + * + *

The data is from Unicode's CLDR version 1.7.0. The two currencies + * with non-decimal subunits (MGA and MRO) are marked as having no + * fractional digits as well as all currencies that have no subunits + * in circulation. + * + *

It is "hard-wired" for referential convenience and is only looked + * up when an overriding currencyCode parameter is supplied. + */ + this.currencyFractionDigits = { + "AFN" : 0, "ALL" : 0, "AMD" : 0, "BHD" : 3, "BIF" : 0, + "BYR" : 0, "CLF" : 0, "CLP" : 0, "COP" : 0, "CRC" : 0, + "DJF" : 0, "GNF" : 0, "GYD" : 0, "HUF" : 0, "IDR" : 0, + "IQD" : 0, "IRR" : 0, "ISK" : 0, "JOD" : 3, "JPY" : 0, + "KMF" : 0, "KRW" : 0, "KWD" : 3, "LAK" : 0, "LBP" : 0, + "LYD" : 3, "MGA" : 0, "MMK" : 0, "MNT" : 0, "MRO" : 0, + "MUR" : 0, "OMR" : 3, "PKR" : 0, "PYG" : 0, "RSD" : 0, + "RWF" : 0, "SLL" : 0, "SOS" : 0, "STD" : 0, "SYP" : 0, + "TND" : 3, "TWD" : 0, "TZS" : 0, "UGX" : 0, "UZS" : 0, + "VND" : 0, "VUV" : 0, "XAF" : 0, "XOF" : 0, "XPF" : 0, + "YER" : 0, "ZMK" : 0 + }; + + + // optional currencyCode argument? + if (typeof currencyCode == "string") { + // user wanted to override the local currency + this.currencyCode = currencyCode.toUpperCase(); + + // must override the frac digits too, for some + // currencies have 0, 2 or 3! + var numDigits = this.currencyFractionDigits[this.currencyCode]; + if (typeof numDigits != "number") + numDigits = 2; // default for most currencies + this.lc.frac_digits = numDigits; + this.lc.int_frac_digits = numDigits; + } + else { + // use local currency + this.currencyCode = this.lc.int_curr_symbol.substring(0,3).toUpperCase(); + } + + // extract intl. currency separator + this.intSep = this.lc.int_curr_symbol.charAt(3); + + // flag local or intl. sign formatting? + if (this.currencyCode == this.lc.int_curr_symbol.substring(0,3)) { + // currency matches the local one? -> + // formatting with local symbol and parameters + this.internationalFormatting = false; + this.curSym = this.lc.currency_symbol; + } + else { + // currency doesn't match the local -> + + // do we have an overriding currency symbol? + if (typeof altIntSymbol == "string") { + // -> force formatting with local parameters, using alt symbol + this.curSym = altIntSymbol; + this.internationalFormatting = false; + } + else { + // -> force formatting with intl. sign and parameters + this.internationalFormatting = true; + } + } + + + /** + * @public + * + * @description Gets the currency symbol used in formatting. + * + * @returns {String} The currency symbol. + */ + this.getCurrencySymbol = function() { + + return this.curSym; + }; + + + /** + * @public + * + * @description Gets the position of the currency symbol relative to + * the amount. Assumes a non-negative amount and local formatting. + * + * @param {String} intFlag Optional flag to force international + * formatting by passing the string "i". + * + * @returns {Boolean} True if the symbol precedes the amount, false if + * the symbol succeeds the amount. + */ + this.currencySymbolPrecedes = function(intFlag) { + + if (typeof intFlag == "string" && intFlag == "i") { + // international formatting was forced + if (this.lc.int_p_cs_precedes == 1) + return true; + else + return false; + + } + else { + // check whether local formatting is on or off + if (this.internationalFormatting) { + if (this.lc.int_p_cs_precedes == 1) + return true; + else + return false; + } + else { + if (this.lc.p_cs_precedes == 1) + return true; + else + return false; + } + } + }; + + + /** + * @public + * + * @description Gets the decimal delimiter (radix) used in formatting. + * + * @returns {String} The radix character. + */ + this.getDecimalPoint = function() { + + return this.lc.mon_decimal_point; + }; + + + /** + * @public + * + * @description Gets the number of fractional digits. Assumes local + * formatting. + * + * @param {String} intFlag Optional flag to force international + * formatting by passing the string "i". + * + * @returns {integer Number} The number of fractional digits. + */ + this.getFractionalDigits = function(intFlag) { + + if (typeof intFlag == "string" && intFlag == "i") { + // international formatting was forced + return this.lc.int_frac_digits; + } + else { + // check whether local formatting is on or off + if (this.internationalFormatting) + return this.lc.int_frac_digits; + else + return this.lc.frac_digits; + } + }; + + + /** + * @public + * + * @description Formats a monetary amount according to the preset + * locale. + * + *

+	 * For local currencies the native shorthand symbol will be used for
+	 * formatting.
+	 * Example:
+	 *        locale is en_US
+	 *        currency is USD
+	 *        -> the "$" symbol will be used, e.g. $123.45
+	 *        
+	 * For non-local currencies the international ISO-4217 code will be
+	 * used for formatting.
+	 * Example:
+	 *       locale is en_US (which has USD as currency)
+	 *       currency is EUR
+	 *       -> the ISO three-letter code will be used, e.g. EUR 123.45
+	 *
+	 * If the currency is non-local, but an alternative currency symbol was
+	 * provided, this will be used instead.
+	 * Example
+	 *       locale is en_US (which has USD as currency)
+	 *       currency is EUR
+	 *       an alternative symbol is provided - "€"
+	 *       -> the alternative symbol will be used, e.g. €123.45
+	 * 
+ * + * @param {Number|String} amount The amount to format as currency. + * @param {String} [options] Options to modify the formatted output: + *
    + *
  • "^" suppress grouping + *
  • "!" suppress the currency symbol + *
  • "~" suppress the currency symbol and the sign (positive or negative) + *
  • "i" force international sign (ISO-4217 code) formatting + *
  • ".n" specify decimal precision + * + * @returns The formatted currency amount as string. + * + * @throws "Error: Invalid amount" on bad amount. + */ + this.format = function(amount, options) { + + // if the amount is passed as string, check that it parses to a float + var floatAmount; + + if (typeof amount == "string") { + amount = jsworld._trim(amount); + floatAmount = parseFloat(amount); + + if (typeof floatAmount != "number" || isNaN(floatAmount)) + throw "Error: Amount string not a number"; + } + else if (typeof amount == "number") { + floatAmount = amount; + } + else { + throw "Error: Amount not a number"; + } + + // get the required precision, ".n" option arg overrides default locale config + var reqPrecision = jsworld._getPrecision(options); + + if (reqPrecision == -1) { + if (this.internationalFormatting || jsworld._hasOption("i", options)) + reqPrecision = this.lc.int_frac_digits; + else + reqPrecision = this.lc.frac_digits; + } + + // round + floatAmount = Math.round(floatAmount * Math.pow(10, reqPrecision)) / Math.pow(10, reqPrecision); + + + // convert the float amount to string and parse into + // object with properties integer and fraction + var parsedAmount = jsworld._splitNumber(String(floatAmount)); + + // format integer part with grouping chars + var formattedIntegerPart; + + if (floatAmount === 0) + formattedIntegerPart = "0"; + else + formattedIntegerPart = jsworld._hasOption("^", options) ? + parsedAmount.integer : + jsworld._formatIntegerPart(parsedAmount.integer, + this.lc.mon_grouping, + this.lc.mon_thousands_sep); + + + // format the fractional part + var formattedFractionPart; + + if (reqPrecision == -1) { + // pad fraction with trailing zeros accoring to default locale [int_]frac_digits + if (this.internationalFormatting || jsworld._hasOption("i", options)) + formattedFractionPart = + jsworld._formatFractionPart(parsedAmount.fraction, this.lc.int_frac_digits); + else + formattedFractionPart = + jsworld._formatFractionPart(parsedAmount.fraction, this.lc.frac_digits); + } + else { + // pad fraction with trailing zeros according to optional format parameter + formattedFractionPart = + jsworld._formatFractionPart(parsedAmount.fraction, reqPrecision); + } + + + // join integer and decimal parts using the mon_decimal_point property + var quantity; + + if (this.lc.frac_digits > 0 || formattedFractionPart.length) + quantity = formattedIntegerPart + this.lc.mon_decimal_point + formattedFractionPart; + else + quantity = formattedIntegerPart; + + + // do final formatting with sign and symbol + if (jsworld._hasOption("~", options)) { + return quantity; + } + else { + var suppressSymbol = jsworld._hasOption("!", options) ? true : false; + + var sign = floatAmount < 0 ? "-" : "+"; + + if (this.internationalFormatting || jsworld._hasOption("i", options)) { + + // format with ISO-4217 code (suppressed or not) + if (suppressSymbol) + return this._formatAsInternationalCurrencyWithNoSym(sign, quantity); + else + return this._formatAsInternationalCurrency(sign, quantity); + } + else { + // format with local currency code (suppressed or not) + if (suppressSymbol) + return this._formatAsLocalCurrencyWithNoSym(sign, quantity); + else + return this._formatAsLocalCurrency(sign, quantity); + } + } + }; + + + /** + * @private + * + * @description Assembles the final string with sign, separator and symbol as local + * currency. + * + * @param {String} sign The amount sign: "+" or "-". + * @param {String} q The formatted quantity (unsigned). + * + * @returns {String} The final formatted string. + */ + this._formatAsLocalCurrency = function (sign, q) { + + // assemble final formatted amount by going over all possible value combinations of: + // sign {+,-} , sign position {0,1,2,3,4} , separator {0,1,2} , symbol position {0,1} + if (sign == "+") { + + // parentheses + if (this.lc.p_sign_posn === 0 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 0) { + return "(" + q + this.curSym + ")"; + } + else if (this.lc.p_sign_posn === 0 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 1) { + return "(" + this.curSym + q + ")"; + } + else if (this.lc.p_sign_posn === 0 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 0) { + return "(" + q + " " + this.curSym + ")"; + } + else if (this.lc.p_sign_posn === 0 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 1) { + return "(" + this.curSym + " " + q + ")"; + } + + // sign before q + sym + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 0) { + return this.lc.positive_sign + q + this.curSym; + } + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + this.curSym + q; + } + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 0) { + return this.lc.positive_sign + q + " " + this.curSym; + } + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + this.curSym + " " + q; + } + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 0) { + return this.lc.positive_sign + " " + q + this.curSym; + } + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + " " + this.curSym + q; + } + + // sign after q + sym + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 0) { + return q + this.curSym + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 1) { + return this.curSym + q + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 0) { + return q + " " + this.curSym + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 1) { + return this.curSym + " " + q + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 0) { + return q + this.curSym + " " + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 1) { + return this.curSym + q + " " + this.lc.positive_sign; + } + + // sign before sym + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 0) { + return q + this.lc.positive_sign + this.curSym; + } + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + this.curSym + q; + } + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 0) { + return q + " " + this.lc.positive_sign + this.curSym; + } + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + this.curSym + " " + q; + } + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 0) { + return q + this.lc.positive_sign + " " + this.curSym; + } + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + " " + this.curSym + q; + } + + // sign after symbol + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 0) { + return q + this.curSym + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 1) { + return this.curSym + this.lc.positive_sign + q; + } + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 0) { + return q + " " + this.curSym + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 1) { + return this.curSym + this.lc.positive_sign + " " + q; + } + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 0) { + return q + this.curSym + " " + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 1) { + return this.curSym + " " + this.lc.positive_sign + q; + } + + } + else if (sign == "-") { + + // parentheses enclose q + sym + if (this.lc.n_sign_posn === 0 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 0) { + return "(" + q + this.curSym + ")"; + } + else if (this.lc.n_sign_posn === 0 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 1) { + return "(" + this.curSym + q + ")"; + } + else if (this.lc.n_sign_posn === 0 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 0) { + return "(" + q + " " + this.curSym + ")"; + } + else if (this.lc.n_sign_posn === 0 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 1) { + return "(" + this.curSym + " " + q + ")"; + } + + // sign before q + sym + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 0) { + return this.lc.negative_sign + q + this.curSym; + } + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + this.curSym + q; + } + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 0) { + return this.lc.negative_sign + q + " " + this.curSym; + } + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + this.curSym + " " + q; + } + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 0) { + return this.lc.negative_sign + " " + q + this.curSym; + } + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + " " + this.curSym + q; + } + + // sign after q + sym + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 0) { + return q + this.curSym + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 1) { + return this.curSym + q + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 0) { + return q + " " + this.curSym + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 1) { + return this.curSym + " " + q + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 0) { + return q + this.curSym + " " + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 1) { + return this.curSym + q + " " + this.lc.negative_sign; + } + + // sign before sym + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 0) { + return q + this.lc.negative_sign + this.curSym; + } + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + this.curSym + q; + } + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 0) { + return q + " " + this.lc.negative_sign + this.curSym; + } + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + this.curSym + " " + q; + } + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 0) { + return q + this.lc.negative_sign + " " + this.curSym; + } + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + " " + this.curSym + q; + } + + // sign after symbol + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 0) { + return q + this.curSym + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 1) { + return this.curSym + this.lc.negative_sign + q; + } + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 0) { + return q + " " + this.curSym + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 1) { + return this.curSym + this.lc.negative_sign + " " + q; + } + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 0) { + return q + this.curSym + " " + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 1) { + return this.curSym + " " + this.lc.negative_sign + q; + } + } + + // throw error if we fall through + throw "Error: Invalid POSIX LC MONETARY definition"; + }; + + + /** + * @private + * + * @description Assembles the final string with sign, separator and ISO-4217 + * currency code. + * + * @param {String} sign The amount sign: "+" or "-". + * @param {String} q The formatted quantity (unsigned). + * + * @returns {String} The final formatted string. + */ + this._formatAsInternationalCurrency = function (sign, q) { + + // assemble the final formatted amount by going over all possible value combinations of: + // sign {+,-} , sign position {0,1,2,3,4} , separator {0,1,2} , symbol position {0,1} + + if (sign == "+") { + + // parentheses + if (this.lc.int_p_sign_posn === 0 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 0) { + return "(" + q + this.currencyCode + ")"; + } + else if (this.lc.int_p_sign_posn === 0 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 1) { + return "(" + this.currencyCode + q + ")"; + } + else if (this.lc.int_p_sign_posn === 0 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 0) { + return "(" + q + this.intSep + this.currencyCode + ")"; + } + else if (this.lc.int_p_sign_posn === 0 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 1) { + return "(" + this.currencyCode + this.intSep + q + ")"; + } + + // sign before q + sym + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 0) { + return this.lc.positive_sign + q + this.currencyCode; + } + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.currencyCode + q; + } + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 0) { + return this.lc.positive_sign + q + this.intSep + this.currencyCode; + } + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.currencyCode + this.intSep + q; + } + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 0) { + return this.lc.positive_sign + this.intSep + q + this.currencyCode; + } + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.intSep + this.currencyCode + q; + } + + // sign after q + sym + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 0) { + return q + this.currencyCode + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 1) { + return this.currencyCode + q + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 0) { + return q + this.intSep + this.currencyCode + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 1) { + return this.currencyCode + this.intSep + q + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 0) { + return q + this.currencyCode + this.intSep + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 1) { + return this.currencyCode + q + this.intSep + this.lc.positive_sign; + } + + // sign before sym + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 0) { + return q + this.lc.positive_sign + this.currencyCode; + } + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.currencyCode + q; + } + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 0) { + return q + this.intSep + this.lc.positive_sign + this.currencyCode; + } + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.currencyCode + this.intSep + q; + } + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 0) { + return q + this.lc.positive_sign + this.intSep + this.currencyCode; + } + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.intSep + this.currencyCode + q; + } + + // sign after symbol + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 0) { + return q + this.currencyCode + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 1) { + return this.currencyCode + this.lc.positive_sign + q; + } + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 0) { + return q + this.intSep + this.currencyCode + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 1) { + return this.currencyCode + this.lc.positive_sign + this.intSep + q; + } + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 0) { + return q + this.currencyCode + this.intSep + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 1) { + return this.currencyCode + this.intSep + this.lc.positive_sign + q; + } + + } + else if (sign == "-") { + + // parentheses enclose q + sym + if (this.lc.int_n_sign_posn === 0 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 0) { + return "(" + q + this.currencyCode + ")"; + } + else if (this.lc.int_n_sign_posn === 0 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 1) { + return "(" + this.currencyCode + q + ")"; + } + else if (this.lc.int_n_sign_posn === 0 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 0) { + return "(" + q + this.intSep + this.currencyCode + ")"; + } + else if (this.lc.int_n_sign_posn === 0 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 1) { + return "(" + this.currencyCode + this.intSep + q + ")"; + } + + // sign before q + sym + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 0) { + return this.lc.negative_sign + q + this.currencyCode; + } + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.currencyCode + q; + } + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 0) { + return this.lc.negative_sign + q + this.intSep + this.currencyCode; + } + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.currencyCode + this.intSep + q; + } + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 0) { + return this.lc.negative_sign + this.intSep + q + this.currencyCode; + } + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.intSep + this.currencyCode + q; + } + + // sign after q + sym + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 0) { + return q + this.currencyCode + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 1) { + return this.currencyCode + q + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 0) { + return q + this.intSep + this.currencyCode + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 1) { + return this.currencyCode + this.intSep + q + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 0) { + return q + this.currencyCode + this.intSep + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 1) { + return this.currencyCode + q + this.intSep + this.lc.negative_sign; + } + + // sign before sym + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 0) { + return q + this.lc.negative_sign + this.currencyCode; + } + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.currencyCode + q; + } + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 0) { + return q + this.intSep + this.lc.negative_sign + this.currencyCode; + } + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.currencyCode + this.intSep + q; + } + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 0) { + return q + this.lc.negative_sign + this.intSep + this.currencyCode; + } + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.intSep + this.currencyCode + q; + } + + // sign after symbol + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 0) { + return q + this.currencyCode + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 1) { + return this.currencyCode + this.lc.negative_sign + q; + } + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 0) { + return q + this.intSep + this.currencyCode + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 1) { + return this.currencyCode + this.lc.negative_sign + this.intSep + q; + } + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 0) { + return q + this.currencyCode + this.intSep + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 1) { + return this.currencyCode + this.intSep + this.lc.negative_sign + q; + } + } + + // throw error if we fall through + throw "Error: Invalid POSIX LC MONETARY definition"; + }; + + + /** + * @private + * + * @description Assembles the final string with sign and separator, but suppress the + * local currency symbol. + * + * @param {String} sign The amount sign: "+" or "-". + * @param {String} q The formatted quantity (unsigned). + * + * @returns {String} The final formatted string + */ + this._formatAsLocalCurrencyWithNoSym = function (sign, q) { + + // assemble the final formatted amount by going over all possible value combinations of: + // sign {+,-} , sign position {0,1,2,3,4} , separator {0,1,2} , symbol position {0,1} + + if (sign == "+") { + + // parentheses + if (this.lc.p_sign_posn === 0) { + return "(" + q + ")"; + } + + // sign before q + sym + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 0) { + return this.lc.positive_sign + q; + } + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + q; + } + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 0) { + return this.lc.positive_sign + q; + } + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + q; + } + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 0) { + return this.lc.positive_sign + " " + q; + } + else if (this.lc.p_sign_posn === 1 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + " " + q; + } + + // sign after q + sym + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 0) { + return q + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 1) { + return q + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 0) { + return q + " " + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 1) { + return q + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 0) { + return q + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 2 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 1) { + return q + " " + this.lc.positive_sign; + } + + // sign before sym + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 0) { + return q + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + q; + } + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 0) { + return q + " " + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + " " + q; + } + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 0) { + return q + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 3 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + " " + q; + } + + // sign after symbol + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 0) { + return q + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 0 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + q; + } + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 0) { + return q + " " + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 1 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + " " + q; + } + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 0) { + return q + " " + this.lc.positive_sign; + } + else if (this.lc.p_sign_posn === 4 && this.lc.p_sep_by_space === 2 && this.lc.p_cs_precedes === 1) { + return this.lc.positive_sign + q; + } + + } + else if (sign == "-") { + + // parentheses enclose q + sym + if (this.lc.n_sign_posn === 0) { + return "(" + q + ")"; + } + + // sign before q + sym + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 0) { + return this.lc.negative_sign + q; + } + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + q; + } + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 0) { + return this.lc.negative_sign + q; + } + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + " " + q; + } + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 0) { + return this.lc.negative_sign + " " + q; + } + else if (this.lc.n_sign_posn === 1 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + " " + q; + } + + // sign after q + sym + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 0) { + return q + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 1) { + return q + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 0) { + return q + " " + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 1) { + return q + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 0) { + return q + " " + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 2 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 1) { + return q + " " + this.lc.negative_sign; + } + + // sign before sym + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 0) { + return q + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + q; + } + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 0) { + return q + " " + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + " " + q; + } + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 0) { + return q + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 3 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + " " + q; + } + + // sign after symbol + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 0) { + return q + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 0 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + q; + } + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 0) { + return q + " " + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 1 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + " " + q; + } + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 0) { + return q + " " + this.lc.negative_sign; + } + else if (this.lc.n_sign_posn === 4 && this.lc.n_sep_by_space === 2 && this.lc.n_cs_precedes === 1) { + return this.lc.negative_sign + q; + } + } + + // throw error if we fall through + throw "Error: Invalid POSIX LC MONETARY definition"; + }; + + + /** + * @private + * + * @description Assembles the final string with sign and separator, but suppress + * the ISO-4217 currency code. + * + * @param {String} sign The amount sign: "+" or "-". + * @param {String} q The formatted quantity (unsigned). + * + * @returns {String} The final formatted string. + */ + this._formatAsInternationalCurrencyWithNoSym = function (sign, q) { + + // assemble the final formatted amount by going over all possible value combinations of: + // sign {+,-} , sign position {0,1,2,3,4} , separator {0,1,2} , symbol position {0,1} + + if (sign == "+") { + + // parentheses + if (this.lc.int_p_sign_posn === 0) { + return "(" + q + ")"; + } + + // sign before q + sym + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 0) { + return this.lc.positive_sign + q; + } + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + q; + } + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 0) { + return this.lc.positive_sign + q; + } + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.intSep + q; + } + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 0) { + return this.lc.positive_sign + this.intSep + q; + } + else if (this.lc.int_p_sign_posn === 1 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.intSep + q; + } + + // sign after q + sym + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 0) { + return q + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 1) { + return q + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 0) { + return q + this.intSep + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 1) { + return q + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 0) { + return q + this.intSep + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 2 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 1) { + return q + this.intSep + this.lc.positive_sign; + } + + // sign before sym + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 0) { + return q + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + q; + } + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 0) { + return q + this.intSep + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.intSep + q; + } + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 0) { + return q + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 3 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.intSep + q; + } + + // sign after symbol + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 0) { + return q + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 0 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + q; + } + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 0) { + return q + this.intSep + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 1 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + this.intSep + q; + } + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 0) { + return q + this.intSep + this.lc.positive_sign; + } + else if (this.lc.int_p_sign_posn === 4 && this.lc.int_p_sep_by_space === 2 && this.lc.int_p_cs_precedes === 1) { + return this.lc.positive_sign + q; + } + + } + else if (sign == "-") { + + // parentheses enclose q + sym + if (this.lc.int_n_sign_posn === 0) { + return "(" + q + ")"; + } + + // sign before q + sym + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 0) { + return this.lc.negative_sign + q; + } + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + q; + } + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 0) { + return this.lc.negative_sign + q; + } + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.intSep + q; + } + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 0) { + return this.lc.negative_sign + this.intSep + q; + } + else if (this.lc.int_n_sign_posn === 1 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.intSep + q; + } + + // sign after q + sym + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 0) { + return q + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 1) { + return q + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 0) { + return q + this.intSep + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 1) { + return q + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 0) { + return q + this.intSep + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 2 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 1) { + return q + this.intSep + this.lc.negative_sign; + } + + // sign before sym + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 0) { + return q + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + q; + } + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 0) { + return q + this.intSep + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.intSep + q; + } + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 0) { + return q + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 3 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.intSep + q; + } + + // sign after symbol + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 0) { + return q + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 0 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + q; + } + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 0) { + return q + this.intSep + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 1 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + this.intSep + q; + } + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 0) { + return q + this.intSep + this.lc.negative_sign; + } + else if (this.lc.int_n_sign_posn === 4 && this.lc.int_n_sep_by_space === 2 && this.lc.int_n_cs_precedes === 1) { + return this.lc.negative_sign + q; + } + } + + // throw error if we fall through + throw "Error: Invalid POSIX LC_MONETARY definition"; + }; +}; + + +/** + * @class + * Class for parsing localised number strings. + * + * @public + * @constructor + * @description Creates a new numeric parser for the specified locale. + * + * @param {jsworld.Locale} locale A locale object specifying the required + * POSIX LC_NUMERIC formatting properties. + * + * @throws Error on constructor failure. + */ +jsworld.NumericParser = function(locale) { + + if (typeof locale != "object" || locale._className != "jsworld.Locale") + throw "Constructor error: You must provide a valid jsworld.Locale instance"; + + this.lc = locale; + + + /** + * @public + * + * @description Parses a numeric string formatted according to the + * preset locale. Leading and trailing whitespace is ignored; the number + * may also be formatted without thousands separators. + * + * @param {String} formattedNumber The formatted number. + * + * @returns {Number} The parsed number. + * + * @throws Error on a parse exception. + */ + this.parse = function(formattedNumber) { + + if (typeof formattedNumber != "string") + throw "Parse error: Argument must be a string"; + + // trim whitespace + var s = jsworld._trim(formattedNumber); + + // remove any thousand separator symbols + s = jsworld._stringReplaceAll(formattedNumber, this.lc.thousands_sep, ""); + + // replace any local decimal point symbols with the symbol used + // in JavaScript "." + s = jsworld._stringReplaceAll(s, this.lc.decimal_point, "."); + + // test if the string represents a number + if (jsworld._isNumber(s)) + return parseFloat(s, 10); + else + throw "Parse error: Invalid number string"; + }; +}; + + +/** + * @class + * Class for parsing localised date and time strings. + * + * @public + * @constructor + * @description Creates a new date/time parser for the specified locale. + * + * @param {jsworld.Locale} locale A locale object specifying the required + * POSIX LC_TIME formatting properties. + * + * @throws Error on constructor failure. + */ +jsworld.DateTimeParser = function(locale) { + + if (typeof locale != "object" || locale._className != "jsworld.Locale") + throw "Constructor error: You must provide a valid jsworld.Locale instance."; + + this.lc = locale; + + + /** + * @public + * + * @description Parses a time string formatted according to the + * POSIX LC_TIME t_fmt property of the preset locale. + * + * @param {String} formattedTime The formatted time. + * + * @returns {String} The parsed time in ISO-8601 format (HH:MM:SS), e.g. + * "23:59:59". + * + * @throws Error on a parse exception. + */ + this.parseTime = function(formattedTime) { + + if (typeof formattedTime != "string") + throw "Parse error: Argument must be a string"; + + var dt = this._extractTokens(this.lc.t_fmt, formattedTime); + + var timeDefined = false; + + if (dt.hour !== null && dt.minute !== null && dt.second !== null) { + timeDefined = true; + } + else if (dt.hourAmPm !== null && dt.am !== null && dt.minute !== null && dt.second !== null) { + if (dt.am) { + // AM [12(midnight), 1 .. 11] + if (dt.hourAmPm == 12) + dt.hour = 0; + else + dt.hour = parseInt(dt.hourAmPm, 10); + } + else { + // PM [12(noon), 1 .. 11] + if (dt.hourAmPm == 12) + dt.hour = 12; + else + dt.hour = parseInt(dt.hourAmPm, 10) + 12; + } + timeDefined = true; + } + + if (timeDefined) + return jsworld._zeroPad(dt.hour, 2) + + ":" + + jsworld._zeroPad(dt.minute, 2) + + ":" + + jsworld._zeroPad(dt.second, 2); + else + throw "Parse error: Invalid/ambiguous time string"; + }; + + + /** + * @public + * + * @description Parses a date string formatted according to the + * POSIX LC_TIME d_fmt property of the preset locale. + * + * @param {String} formattedDate The formatted date, must be valid. + * + * @returns {String} The parsed date in ISO-8601 format (YYYY-MM-DD), + * e.g. "2010-03-31". + * + * @throws Error on a parse exception. + */ + this.parseDate = function(formattedDate) { + + if (typeof formattedDate != "string") + throw "Parse error: Argument must be a string"; + + var dt = this._extractTokens(this.lc.d_fmt, formattedDate); + + var dateDefined = false; + + if (dt.year !== null && dt.month !== null && dt.day !== null) { + dateDefined = true; + } + + if (dateDefined) + return jsworld._zeroPad(dt.year, 4) + + "-" + + jsworld._zeroPad(dt.month, 2) + + "-" + + jsworld._zeroPad(dt.day, 2); + else + throw "Parse error: Invalid date string"; + }; + + + /** + * @public + * + * @description Parses a date/time string formatted according to the + * POSIX LC_TIME d_t_fmt property of the preset locale. + * + * @param {String} formattedDateTime The formatted date/time, must be + * valid. + * + * @returns {String} The parsed date/time in ISO-8601 format + * (YYYY-MM-DD HH:MM:SS), e.g. "2010-03-31 23:59:59". + * + * @throws Error on a parse exception. + */ + this.parseDateTime = function(formattedDateTime) { + + if (typeof formattedDateTime != "string") + throw "Parse error: Argument must be a string"; + + var dt = this._extractTokens(this.lc.d_t_fmt, formattedDateTime); + + var timeDefined = false; + var dateDefined = false; + + if (dt.hour !== null && dt.minute !== null && dt.second !== null) { + timeDefined = true; + } + else if (dt.hourAmPm !== null && dt.am !== null && dt.minute !== null && dt.second !== null) { + if (dt.am) { + // AM [12(midnight), 1 .. 11] + if (dt.hourAmPm == 12) + dt.hour = 0; + else + dt.hour = parseInt(dt.hourAmPm, 10); + } + else { + // PM [12(noon), 1 .. 11] + if (dt.hourAmPm == 12) + dt.hour = 12; + else + dt.hour = parseInt(dt.hourAmPm, 10) + 12; + } + timeDefined = true; + } + + if (dt.year !== null && dt.month !== null && dt.day !== null) { + dateDefined = true; + } + + if (dateDefined && timeDefined) + return jsworld._zeroPad(dt.year, 4) + + "-" + + jsworld._zeroPad(dt.month, 2) + + "-" + + jsworld._zeroPad(dt.day, 2) + + " " + + jsworld._zeroPad(dt.hour, 2) + + ":" + + jsworld._zeroPad(dt.minute, 2) + + ":" + + jsworld._zeroPad(dt.second, 2); + else + throw "Parse error: Invalid/ambiguous date/time string"; + }; + + + /** + * @private + * + * @description Parses a string according to the specified format + * specification. + * + * @param {String} fmtSpec The format specification, e.g. "%I:%M:%S %p". + * @param {String} s The string to parse. + * + * @returns {object} An object with set properties year, month, day, + * hour, minute and second if the corresponding values are + * found in the parsed string. + * + * @throws Error on a parse exception. + */ + this._extractTokens = function(fmtSpec, s) { + + // the return object containing the parsed date/time properties + var dt = { + // for date and date/time strings + "year" : null, + "month" : null, + "day" : null, + + // for time and date/time strings + "hour" : null, + "hourAmPm" : null, + "am" : null, + "minute" : null, + "second" : null, + + // used internally only + "weekday" : null + }; + + + // extract and process each token in the date/time spec + while (fmtSpec.length > 0) { + + // Do we have a valid "%\w" placeholder in stream? + if (fmtSpec.charAt(0) == "%" && fmtSpec.charAt(1) != "") { + + // get placeholder + var placeholder = fmtSpec.substring(0,2); + + if (placeholder == "%%") { + // escaped '%'' + s = s.substring(1); + } + else if (placeholder == "%a") { + // abbreviated weekday name + for (var i = 0; i < this.lc.abday.length; i++) { + + if (jsworld._stringStartsWith(s, this.lc.abday[i])) { + dt.weekday = i; + s = s.substring(this.lc.abday[i].length); + break; + } + } + + if (dt.weekday === null) + throw "Parse error: Unrecognised abbreviated weekday name (%a)"; + } + else if (placeholder == "%A") { + // weekday name + for (var i = 0; i < this.lc.day.length; i++) { + + if (jsworld._stringStartsWith(s, this.lc.day[i])) { + dt.weekday = i; + s = s.substring(this.lc.day[i].length); + break; + } + } + + if (dt.weekday === null) + throw "Parse error: Unrecognised weekday name (%A)"; + } + else if (placeholder == "%b" || placeholder == "%h") { + // abbreviated month name + for (var i = 0; i < this.lc.abmon.length; i++) { + + if (jsworld._stringStartsWith(s, this.lc.abmon[i])) { + dt.month = i + 1; + s = s.substring(this.lc.abmon[i].length); + break; + } + } + + if (dt.month === null) + throw "Parse error: Unrecognised abbreviated month name (%b)"; + } + else if (placeholder == "%B") { + // month name + for (var i = 0; i < this.lc.mon.length; i++) { + + if (jsworld._stringStartsWith(s, this.lc.mon[i])) { + dt.month = i + 1; + s = s.substring(this.lc.mon[i].length); + break; + } + } + + if (dt.month === null) + throw "Parse error: Unrecognised month name (%B)"; + } + else if (placeholder == "%d") { + // day of the month [01..31] + if (/^0[1-9]|[1-2][0-9]|3[0-1]/.test(s)) { + dt.day = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised day of the month (%d)"; + } + else if (placeholder == "%e") { + // day of the month [1..31] + + // Note: if %e is leading in fmt string -> space padded! + + var day = s.match(/^\s?(\d{1,2})/); + dt.day = parseInt(day, 10); + + if (isNaN(dt.day) || dt.day < 1 || dt.day > 31) + throw "Parse error: Unrecognised day of the month (%e)"; + + s = s.substring(day.length); + } + else if (placeholder == "%F") { + // equivalent to %Y-%m-%d (ISO-8601 date format) + + // year [nnnn] + if (/^\d\d\d\d/.test(s)) { + dt.year = parseInt(s.substring(0,4), 10); + s = s.substring(4); + } + else { + throw "Parse error: Unrecognised date (%F)"; + } + + // - + if (jsworld._stringStartsWith(s, "-")) + s = s.substring(1); + else + throw "Parse error: Unrecognised date (%F)"; + + // month [01..12] + if (/^0[1-9]|1[0-2]/.test(s)) { + dt.month = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised date (%F)"; + + // - + if (jsworld._stringStartsWith(s, "-")) + s = s.substring(1); + else + throw "Parse error: Unrecognised date (%F)"; + + // day of the month [01..31] + if (/^0[1-9]|[1-2][0-9]|3[0-1]/.test(s)) { + dt.day = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised date (%F)"; + } + else if (placeholder == "%H") { + // hour [00..23] + if (/^[0-1][0-9]|2[0-3]/.test(s)) { + dt.hour = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised hour (%H)"; + } + else if (placeholder == "%I") { + // hour [01..12] + if (/^0[1-9]|1[0-2]/.test(s)) { + dt.hourAmPm = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised hour (%I)"; + } + else if (placeholder == "%k") { + // hour [0..23] + var h = s.match(/^(\d{1,2})/); + dt.hour = parseInt(h, 10); + + if (isNaN(dt.hour) || dt.hour < 0 || dt.hour > 23) + throw "Parse error: Unrecognised hour (%k)"; + + s = s.substring(h.length); + } + else if (placeholder == "%l") { + // hour AM/PM [1..12] + var h = s.match(/^(\d{1,2})/); + dt.hourAmPm = parseInt(h, 10); + + if (isNaN(dt.hourAmPm) || dt.hourAmPm < 1 || dt.hourAmPm > 12) + throw "Parse error: Unrecognised hour (%l)"; + + s = s.substring(h.length); + } + else if (placeholder == "%m") { + // month [01..12] + if (/^0[1-9]|1[0-2]/.test(s)) { + dt.month = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised month (%m)"; + } + else if (placeholder == "%M") { + // minute [00..59] + if (/^[0-5][0-9]/.test(s)) { + dt.minute = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised minute (%M)"; + } + else if (placeholder == "%n") { + // new line + + if (s.charAt(0) == "\n") + s = s.substring(1); + else + throw "Parse error: Unrecognised new line (%n)"; + } + else if (placeholder == "%p") { + // locale's equivalent of AM/PM + if (jsworld._stringStartsWith(s, this.lc.am)) { + dt.am = true; + s = s.substring(this.lc.am.length); + } + else if (jsworld._stringStartsWith(s, this.lc.pm)) { + dt.am = false; + s = s.substring(this.lc.pm.length); + } + else + throw "Parse error: Unrecognised AM/PM value (%p)"; + } + else if (placeholder == "%P") { + // same as %p but forced lower case + if (jsworld._stringStartsWith(s, this.lc.am.toLowerCase())) { + dt.am = true; + s = s.substring(this.lc.am.length); + } + else if (jsworld._stringStartsWith(s, this.lc.pm.toLowerCase())) { + dt.am = false; + s = s.substring(this.lc.pm.length); + } + else + throw "Parse error: Unrecognised AM/PM value (%P)"; + } + else if (placeholder == "%R") { + // same as %H:%M + + // hour [00..23] + if (/^[0-1][0-9]|2[0-3]/.test(s)) { + dt.hour = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised time (%R)"; + + // : + if (jsworld._stringStartsWith(s, ":")) + s = s.substring(1); + else + throw "Parse error: Unrecognised time (%R)"; + + // minute [00..59] + if (/^[0-5][0-9]/.test(s)) { + dt.minute = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised time (%R)"; + + } + else if (placeholder == "%S") { + // second [00..59] + if (/^[0-5][0-9]/.test(s)) { + dt.second = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised second (%S)"; + } + else if (placeholder == "%T") { + // same as %H:%M:%S + + // hour [00..23] + if (/^[0-1][0-9]|2[0-3]/.test(s)) { + dt.hour = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised time (%T)"; + + // : + if (jsworld._stringStartsWith(s, ":")) + s = s.substring(1); + else + throw "Parse error: Unrecognised time (%T)"; + + // minute [00..59] + if (/^[0-5][0-9]/.test(s)) { + dt.minute = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised time (%T)"; + + // : + if (jsworld._stringStartsWith(s, ":")) + s = s.substring(1); + else + throw "Parse error: Unrecognised time (%T)"; + + // second [00..59] + if (/^[0-5][0-9]/.test(s)) { + dt.second = parseInt(s.substring(0,2), 10); + s = s.substring(2); + } + else + throw "Parse error: Unrecognised time (%T)"; + } + else if (placeholder == "%w") { + // weekday [0..6] + if (/^\d/.test(s)) { + dt.weekday = parseInt(s.substring(0,1), 10); + s = s.substring(1); + } + else + throw "Parse error: Unrecognised weekday number (%w)"; + } + else if (placeholder == "%y") { + // year [00..99] + if (/^\d\d/.test(s)) { + var year2digits = parseInt(s.substring(0,2), 10); + + // this conversion to year[nnnn] is arbitrary!!! + if (year2digits > 50) + dt.year = 1900 + year2digits; + else + dt.year = 2000 + year2digits; + + s = s.substring(2); + } + else + throw "Parse error: Unrecognised year (%y)"; + } + else if (placeholder == "%Y") { + // year [nnnn] + if (/^\d\d\d\d/.test(s)) { + dt.year = parseInt(s.substring(0,4), 10); + s = s.substring(4); + } + else + throw "Parse error: Unrecognised year (%Y)"; + } + + else if (placeholder == "%Z") { + // time-zone place holder is not supported + + if (fmtSpec.length === 0) + break; // ignore rest of fmt spec + } + + // remove the spec placeholder that was just parsed + fmtSpec = fmtSpec.substring(2); + } + else { + // If we don't have a placeholder, the chars + // at pos. 0 of format spec and parsed string must match + + // Note: Space chars treated 1:1 ! + + if (fmtSpec.charAt(0) != s.charAt(0)) + throw "Parse error: Unexpected symbol \"" + s.charAt(0) + "\" in date/time string"; + + fmtSpec = fmtSpec.substring(1); + s = s.substring(1); + } + } + + // parsing finished, return composite date/time object + return dt; + }; +}; + + +/** + * @class + * Class for parsing localised currency amount strings. + * + * @public + * @constructor + * @description Creates a new monetary parser for the specified locale. + * + * @param {jsworld.Locale} locale A locale object specifying the required + * POSIX LC_MONETARY formatting properties. + * + * @throws Error on constructor failure. + */ +jsworld.MonetaryParser = function(locale) { + + if (typeof locale != "object" || locale._className != "jsworld.Locale") + throw "Constructor error: You must provide a valid jsworld.Locale instance"; + + + this.lc = locale; + + + /** + * @public + * + * @description Parses a currency amount string formatted according to + * the preset locale. Leading and trailing whitespace is ignored; the + * amount may also be formatted without thousands separators. Both + * the local (shorthand) symbol and the ISO 4217 code are accepted to + * designate the currency in the formatted amount. + * + * @param {String} formattedCurrency The formatted currency amount. + * + * @returns {Number} The parsed amount. + * + * @throws Error on a parse exception. + */ + this.parse = function(formattedCurrency) { + + if (typeof formattedCurrency != "string") + throw "Parse error: Argument must be a string"; + + // Detect the format type and remove the currency symbol + var symbolType = this._detectCurrencySymbolType(formattedCurrency); + + var formatType, s; + + if (symbolType == "local") { + formatType = "local"; + s = formattedCurrency.replace(this.lc.getCurrencySymbol(), ""); + } + else if (symbolType == "int") { + formatType = "int"; + s = formattedCurrency.replace(this.lc.getIntCurrencySymbol(), ""); + } + else if (symbolType == "none") { + formatType = "local"; // assume local + s = formattedCurrency; + } + else + throw "Parse error: Internal assert failure"; + + // Remove any thousands separators + s = jsworld._stringReplaceAll(s, this.lc.mon_thousands_sep, ""); + + // Replace any local radix char with JavaScript's "." + s = s.replace(this.lc.mon_decimal_point, "."); + + // Remove all whitespaces + s = s.replace(/\s*/g, ""); + + // Remove any local non-negative sign + s = this._removeLocalNonNegativeSign(s, formatType); + + // Replace any local minus sign with JavaScript's "-" and put + // it in front of the amount if necessary + // (special parentheses rule checked too) + s = this._normaliseNegativeSign(s, formatType); + + // Finally, we should be left with a bare parsable decimal number + if (jsworld._isNumber(s)) + return parseFloat(s, 10); + else + throw "Parse error: Invalid currency amount string"; + }; + + + /** + * @private + * + * @description Tries to detect the symbol type used in the specified + * formatted currency string: local(shorthand), + * international (ISO-4217 code) or none. + * + * @param {String} formattedCurrency The the formatted currency string. + * + * @return {String} With possible values "local", "int" or "none". + */ + this._detectCurrencySymbolType = function(formattedCurrency) { + + // Check for whichever sign (int/local) is longer first + // to cover cases such as MOP/MOP$ and ZAR/R + + if (this.lc.getCurrencySymbol().length > this.lc.getIntCurrencySymbol().length) { + + if (formattedCurrency.indexOf(this.lc.getCurrencySymbol()) != -1) + return "local"; + else if (formattedCurrency.indexOf(this.lc.getIntCurrencySymbol()) != -1) + return "int"; + else + return "none"; + } + else { + if (formattedCurrency.indexOf(this.lc.getIntCurrencySymbol()) != -1) + return "int"; + else if (formattedCurrency.indexOf(this.lc.getCurrencySymbol()) != -1) + return "local"; + else + return "none"; + } + }; + + + /** + * @private + * + * @description Removes a local non-negative sign in a formatted + * currency string if it is found. This is done according to the + * locale properties p_sign_posn and int_p_sign_posn. + * + * @param {String} s The input string. + * @param {String} formatType With possible values "local" or "int". + * + * @returns {String} The processed string. + */ + this._removeLocalNonNegativeSign = function(s, formatType) { + + s = s.replace(this.lc.positive_sign, ""); + + // check for enclosing parentheses rule + if (((formatType == "local" && this.lc.p_sign_posn === 0) || + (formatType == "int" && this.lc.int_p_sign_posn === 0) ) && + /\(\d+\.?\d*\)/.test(s)) { + s = s.replace("(", ""); + s = s.replace(")", ""); + } + + return s; + }; + + + /** + * @private + * + * @description Replaces a local negative sign with the standard + * JavaScript minus ("-") sign placed in the correct position + * (preceding the amount). This is done according to the locale + * properties for negative sign symbol and relative position. + * + * @param {String} s The input string. + * @param {String} formatType With possible values "local" or "int". + * + * @returns {String} The processed string. + */ + this._normaliseNegativeSign = function(s, formatType) { + + // replace local negative symbol with JavaScript's "-" + s = s.replace(this.lc.negative_sign, "-"); + + // check for enclosing parentheses rule and replace them + // with negative sign before the amount + if ((formatType == "local" && this.lc.n_sign_posn === 0) || + (formatType == "int" && this.lc.int_n_sign_posn === 0) ) { + + if (/^\(\d+\.?\d*\)$/.test(s)) { + + s = s.replace("(", ""); + s = s.replace(")", ""); + return "-" + s; + } + } + + // check for rule negative sign succeeding the amount + if (formatType == "local" && this.lc.n_sign_posn == 2 || + formatType == "int" && this.lc.int_n_sign_posn == 2 ) { + + if (/^\d+\.?\d*-$/.test(s)) { + s = s.replace("-", ""); + return "-" + s; + } + } + + // check for rule cur. sym. succeeds and sign adjacent + if (formatType == "local" && this.lc.n_cs_precedes === 0 && this.lc.n_sign_posn == 3 || + formatType == "local" && this.lc.n_cs_precedes === 0 && this.lc.n_sign_posn == 4 || + formatType == "int" && this.lc.int_n_cs_precedes === 0 && this.lc.int_n_sign_posn == 3 || + formatType == "int" && this.lc.int_n_cs_precedes === 0 && this.lc.int_n_sign_posn == 4 ) { + + if (/^\d+\.?\d*-$/.test(s)) { + s = s.replace("-", ""); + return "-" + s; + } + } + + return s; + }; +}; + +// end-of-file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs2.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs2.js new file mode 100644 index 00000000..4e9f9672 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs2.js @@ -0,0 +1,166 @@ +jsworld.Locale = function(properties) { + + // LC_NUMERIC + + + this.frac_digits = properties.frac_digits; + + + // may be empty string/null for currencies with no fractional part + if (properties.mon_decimal_point === null || properties.mon_decimal_point == "") { + + if (this.frac_digits > 0) + throw "Error: Undefined mon_decimal_point property"; + else + properties.mon_decimal_point = ""; + } + + if (typeof properties.mon_decimal_point != "string") + throw "Error: Invalid/missing mon_decimal_point property"; + + this.mon_decimal_point = properties.mon_decimal_point; + + + if (typeof properties.mon_thousands_sep != "string") + throw "Error: Invalid/missing mon_thousands_sep property"; + + this.mon_thousands_sep = properties.mon_thousands_sep; + + + if (typeof properties.mon_grouping != "string") + throw "Error: Invalid/missing mon_grouping property"; + + this.mon_grouping = properties.mon_grouping; + + + if (typeof properties.positive_sign != "string") + throw "Error: Invalid/missing positive_sign property"; + + this.positive_sign = properties.positive_sign; + + + if (typeof properties.negative_sign != "string") + throw "Error: Invalid/missing negative_sign property"; + + this.negative_sign = properties.negative_sign; + + + if (properties.p_cs_precedes !== 0 && properties.p_cs_precedes !== 1) + throw "Error: Invalid/missing p_cs_precedes property, must be 0 or 1"; + + this.p_cs_precedes = properties.p_cs_precedes; + + + if (properties.n_cs_precedes !== 0 && properties.n_cs_precedes !== 1) + throw "Error: Invalid/missing n_cs_precedes, must be 0 or 1"; + + this.n_cs_precedes = properties.n_cs_precedes; + + + if (properties.p_sep_by_space !== 0 && + properties.p_sep_by_space !== 1 && + properties.p_sep_by_space !== 2) + throw "Error: Invalid/missing p_sep_by_space property, must be 0, 1 or 2"; + + this.p_sep_by_space = properties.p_sep_by_space; + + + if (properties.n_sep_by_space !== 0 && + properties.n_sep_by_space !== 1 && + properties.n_sep_by_space !== 2) + throw "Error: Invalid/missing n_sep_by_space property, must be 0, 1, or 2"; + + this.n_sep_by_space = properties.n_sep_by_space; + + + if (properties.p_sign_posn !== 0 && + properties.p_sign_posn !== 1 && + properties.p_sign_posn !== 2 && + properties.p_sign_posn !== 3 && + properties.p_sign_posn !== 4) + throw "Error: Invalid/missing p_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.p_sign_posn = properties.p_sign_posn; + + + if (properties.n_sign_posn !== 0 && + properties.n_sign_posn !== 1 && + properties.n_sign_posn !== 2 && + properties.n_sign_posn !== 3 && + properties.n_sign_posn !== 4) + throw "Error: Invalid/missing n_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.n_sign_posn = properties.n_sign_posn; + + + if (typeof properties.int_frac_digits != "number" && properties.int_frac_digits < 0) + throw "Error: Invalid/missing int_frac_digits property"; + + this.int_frac_digits = properties.int_frac_digits; + + + if (properties.int_p_cs_precedes !== 0 && properties.int_p_cs_precedes !== 1) + throw "Error: Invalid/missing int_p_cs_precedes property, must be 0 or 1"; + + this.int_p_cs_precedes = properties.int_p_cs_precedes; + + + if (properties.int_n_cs_precedes !== 0 && properties.int_n_cs_precedes !== 1) + throw "Error: Invalid/missing int_n_cs_precedes property, must be 0 or 1"; + + this.int_n_cs_precedes = properties.int_n_cs_precedes; + + + if (properties.int_p_sep_by_space !== 0 && + properties.int_p_sep_by_space !== 1 && + properties.int_p_sep_by_space !== 2) + throw "Error: Invalid/missing int_p_sep_by_spacev, must be 0, 1 or 2"; + + this.int_p_sep_by_space = properties.int_p_sep_by_space; + + + if (properties.int_n_sep_by_space !== 0 && + properties.int_n_sep_by_space !== 1 && + properties.int_n_sep_by_space !== 2) + throw "Error: Invalid/missing int_n_sep_by_space property, must be 0, 1, or 2"; + + this.int_n_sep_by_space = properties.int_n_sep_by_space; + + + if (properties.int_p_sign_posn !== 0 && + properties.int_p_sign_posn !== 1 && + properties.int_p_sign_posn !== 2 && + properties.int_p_sign_posn !== 3 && + properties.int_p_sign_posn !== 4) + throw "Error: Invalid/missing int_p_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.int_p_sign_posn = properties.int_p_sign_posn; + + + if (properties.int_n_sign_posn !== 0 && + properties.int_n_sign_posn !== 1 && + properties.int_n_sign_posn !== 2 && + properties.int_n_sign_posn !== 3 && + properties.int_n_sign_posn !== 4) + throw "Error: Invalid/missing int_n_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.int_n_sign_posn = properties.int_n_sign_posn; + + + // LC_TIME + + if (properties == null || typeof properties != "object") + throw "Error: Invalid/missing time locale properties"; + + + // parse the supported POSIX LC_TIME properties + + // abday + try { + this.abday = this._parseList(properties.abday, 7); + } + catch (error) { + throw "Error: Invalid abday property: " + error; + } + +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/uglify-js.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/uglify-js.js new file mode 100644 index 00000000..4305e232 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/uglify-js.js @@ -0,0 +1,17 @@ +//convienence function(src, [options]); +function uglify(orig_code, options){ + options || (options = {}); + var jsp = uglify.parser; + var pro = uglify.uglify; + + var ast = jsp.parse(orig_code, options.strict_semicolons); // parse code and get the initial AST + ast = pro.ast_mangle(ast, options.mangle_options); // get a new AST with mangled names + ast = pro.ast_squeeze(ast, options.squeeze_options); // get an AST with compression optimizations + var final_code = pro.gen_code(ast, options.gen_options); // compressed code here + return final_code; +}; + +uglify.parser = require("./lib/parse-js"); +uglify.uglify = require("./lib/process"); + +module.exports = uglify \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/.npmignore b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/.npmignore new file mode 100644 index 00000000..82337939 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/.npmignore @@ -0,0 +1,6 @@ +npm-debug.log +node_modules +.*.swp +.lock-* +build + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/.travis.yml b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/.travis.yml new file mode 100644 index 00000000..08e4dad6 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +npm_args: --ws:native +node_js: + - "0.6" + - "0.8" + - "0.10" diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/History.md b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/History.md new file mode 100644 index 00000000..63cf0ea6 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/History.md @@ -0,0 +1,312 @@ +v0.4.31 - September 23th, 2013 +===================== + +* Component support + +v0.4.30 - August 30th, 2013 +===================== + +* BufferedAmount could be undefined, default to 0 [TooTallNate] +* Support protocols as second argument and options as third [TooTallNate] +* Proper browserify shim [mcollina] +* Broadcasting example in README [stefanocudini] + +v0.4.29 - August 23th, 2013 +===================== +* Small clean up of the Node 0.11 support by using NAN from the NPM registry [kkoopa] +* Support for custom `Agent`'s through the options. [gramakri] & [TooTallNate] +* Support for custom headers through the options [3rd-Eden] +* Added a `gypfile` flag to the package.json for compiled module discovery [wolfeidau] + +v0.4.28 - August 16th, 2013 +===================== +* Node 0.11 support. [kkoopa] +* Authorization headers are sent when basic auth is used in the url [jcrugzz] +* Origin header will now include the port number [Jason Plum] +* Race condition fixed where data was received before the readyState was updated. [saschagehlich] + +v0.4.27 - June 27th, 2013 +===================== +* Frames are no longer masked in `wscat`. [slaskis] +* Don't retrain reference to large slab buffers. [jmatthewsr-msi] +* Don't use Buffer.byteLength for ArrayBuffer's. [Anthony Pesch] +* Fix browser field in package.json. [shtylman] +* Client-side certificate support & documentation improvements. [Lukas Berns] +* WebSocket readyState's is added to the prototype for spec compatiblity. [BallBearing] +* Use Object.defineProperty. [arlolra] +* Autodetect ArrayBuffers as binary when sending. [BallBearing] +* Check instanceof Buffer for binary data. [arlolra] +* Emit the close event before destroying the internal socket. [3rd-Eden] +* Don't setup multiply timeouts for one connection. [AndreasMadsen] +* Allow support for binding to ethereal port. [wpreul] +* Fix broken terminate reference. [3rd-Eden] +* Misc node 0.10 test fixes and documentation improvements. [3rd-Eden] +* Ensure ssl options are propagated to request. [einaros] +* Add 'Host' and 'Origin' to request header. [Lars-Magnus Skog] +* Subprotocol support. [kanaka] +* Honor ArrayBufferView's byteOffset when sending. [Anthony Pesch] +* Added target attribute for events. [arlolra] + +v0.4.26 - Skipped +===================== + +v0.4.25 - December 17th, 2012 +===================== +* Removed install.js. [shtylman] +* Added browser field to package.json. [shtylman] +* Support overwriting host header. [Raynos] +* Emit 'listening' also with custom http server. [sebiq] + +v0.4.24 - December 6th, 2012 +===================== +* Yet another intermediate release, to not delay minor features any longer. +* Native support installation issues further circumvented. [einaros] + +v0.4.23 - November 19th, 2012 +===================== +* Service release - last before major upgrade. +* Changes default host from 127.0.0.1 to 0.0.0.0. [einaros] + +v0.4.22 - October 3rd, 2012 +===================== +* clear failsafe cleanup timeout once cleanup is called [AndreasMadsen] +* added w3c compatible CloseEvent for onclose / addEventListener("close", ...). [einaros] +* fix the sub protocol header handler [sonnyp] +* fix unhandled exception if socket closes and 'error' is emitted [jmatthewsr-ms] + +v0.4.21 - July 14th, 2012 +===================== +* Emit error if server reponds with anything other than status code 101. [einaros] +* Added 'headers' event to server. [rauchg] +* path.exists moved to fs.exists. [blakmatrix] + +v0.4.20 - June 26th, 2012 +===================== +* node v0.8.0 compatibility release. + +v0.4.19 - June 19th, 2012 +===================== +* Change sender to merge buffers for relatively small payloads, may improve perf in some cases [einaros] +* Avoid EventEmitter for Receiver classes. As above this may improve perf. [einaros] +* Renamed fallback files from the somewhat misleading '*Windows'. [einaros] + +v0.4.18 - June 14th 2012 +===================== +* Fixed incorrect md5 digest encoding in Hixie handshake [nicokaiser] +* Added example of use with Express 3 [einaros] +* Change installation procedure to not require --ws:native to build native extensions. They will now build if a compiler is available. [einaros] + +v0.4.17 - June 13th 2012 +===================== +* Improve error handling during connection handshaking [einaros] +* Ensure that errors are caught also after connection teardown [nicokaiser] +* Update 'mocha' version to 1.1.0. [einaros] +* Stop showing 'undefined' for some error logs. [tricknotes] +* Update 'should' version to 0.6.3 [tricknotes] + +v0.4.16 - June 1st 2012 +===================== +* Build fix for Windows. [einaros] + +v0.4.15 - May 20th 2012 +===================== +* Enable fauxe streaming for hixie tansport. [einaros] +* Allow hixie sender to deal with buffers. [einaros/pigne] +* Allow error code 1011. [einaros] +* Fix framing for empty packets (empty pings and pongs might break). [einaros] +* Improve error and close handling, to avoid connections lingering in CLOSING state. [einaros] + +v0.4.14 - Apr 30th 2012 +===================== +* use node-gyp instead of node-waf [TooTallNate] +* remove old windows compatibility makefile, and silently fall back to native modules [einaros] +* ensure connection status [nicokaiser] +* websocket client updated to use port 443 by default for wss:// connections [einaros] +* support unix sockets [kschzt] + +v0.4.13 - Apr 12th 2012 +===================== + +* circumvent node 0.6+ related memory leak caused by Object.defineProperty [nicokaiser] +* improved error handling, improving stability in massive load use cases [nicokaiser] + +v0.4.12 - Mar 30th 2012 +===================== + +* various memory leak / possible memory leak cleanups [einaros] +* api documentation [nicokaiser] +* add option to disable client tracking [nicokaiser] + +v0.4.11 - Mar 24th 2012 +===================== + +* node v0.7 compatibillity release +* gyp support [TooTallNate] +* commander dependency update [jwueller] +* loadbalancer support [nicokaiser] + +v0.4.10 - Mar 22th 2012 +===================== + +* Final hixie close frame fixes. [nicokaiser] + +v0.4.9 - Mar 21st 2012 +===================== + +* Various hixie bugfixes (such as proper close frame handling). [einaros] + +v0.4.8 - Feb 29th 2012 +===================== + +* Allow verifyClient to run asynchronously [karlsequin] +* Various bugfixes and cleanups. [einaros] + +v0.4.7 - Feb 21st 2012 +===================== + +* Exposed bytesReceived from websocket client object, which makes it possible to implement bandwidth sampling. [einaros] +* Updated browser based file upload example to include and output per websocket channel bandwidth sampling. [einaros] +* Changed build scripts to check which architecture is currently in use. Required after the node.js changes to have prebuilt packages target ia32 by default. [einaros] + +v0.4.6 - Feb 9th 2012 +===================== + +* Added browser based file upload example. [einaros] +* Added server-to-browser status push example. [einaros] +* Exposed pause() and resume() on WebSocket object, to enable client stream shaping. [einaros] + +v0.4.5 - Feb 7th 2012 +===================== + +* Corrected regression bug in handling of connections with the initial frame delivered across both http upgrade head and a standalone packet. This would lead to a race condition, which in some cases could cause message corruption. [einaros] + +v0.4.4 - Feb 6th 2012 +===================== + +* Pass original request object to verifyClient, for cookie or authentication verifications. [einaros] +* Implemented addEventListener and slightly improved the emulation API by adding a MessageEvent with a readonly data attribute. [aslakhellesoy] +* Rewrite parts of hybi receiver to avoid stack overflows for large amounts of packets bundled in the same buffer / packet. [einaros] + +v0.4.3 - Feb 4th 2012 +===================== + +* Prioritized update: Corrected issue which would cause sockets to stay open longer than necessary, and resource leakage because of this. [einaros] + +v0.4.2 - Feb 4th 2012 +===================== + +* Breaking change: WebSocketServer's verifyOrigin option has been renamed to verifyClient. [einaros] +* verifyClient now receives { origin: 'origin header', secure: true/false }, where 'secure' will be true for ssl connections. [einaros] +* Split benchmark, in preparation for more thorough case. [einaros] +* Introduced hixie-76 draft support for server, since Safari (iPhone / iPad / OS X) and Opera still aren't updated to use Hybi. [einaros] +* Expose 'supports' object from WebSocket, to indicate e.g. the underlying transport's support for binary data. [einaros] +* Test and code cleanups. [einaros] + +v0.4.1 - Jan 25th 2012 +===================== + +* Use readline in wscat [tricknotes] +* Refactor _state away, in favor of the new _readyState [tricknotes] +* travis-ci integration [einaros] +* Fixed race condition in testsuite, causing a few tests to fail (without actually indicating errors) on travis [einaros] +* Expose pong event [paddybyers] +* Enabled running of WebSocketServer in noServer-mode, meaning that upgrades are passed in manually. [einaros] +* Reworked connection procedure for WebSocketServer, and cleaned up tests. [einaros] + +v0.4.0 - Jan 2nd 2012 +===================== + +* Windows compatibility [einaros] +* Windows compatible test script [einaros] + +v0.3.9 - Jan 1st 2012 +====================== + +* Improved protocol framing performance [einaros] +* WSS support [kazuyukitanimura] +* WSS tests [einaros] +* readyState exposed [justinlatimer, tricknotes] +* url property exposed [justinlatimer] +* Removed old 'state' property [einaros] +* Test cleanups [einaros] + +v0.3.8 - Dec 27th 2011 +====================== + +* Made it possible to listen on specific paths, which is especially good to have for precreated http servers [einaros] +* Extensive WebSocket / WebSocketServer cleanup, including changing all internal properties to unconfigurable, unenumerable properties [einaros] +* Receiver modifications to ensure even better performance with fragmented sends [einaros] +* Fixed issue in sender.js, which would cause SlowBuffer instances (such as returned from the crypto library's randomBytes) to be copied (and thus be dead slow) [einaros] +* Removed redundant buffer copy in sender.js, which should improve server performance [einaros] + +v0.3.7 - Dec 25nd 2011 +====================== + +* Added a browser based API which uses EventEmitters internally [3rd-Eden] +* Expose request information from upgrade event for websocket server clients [mmalecki] + +v0.3.6 - Dec 19th 2011 +====================== + +* Added option to let WebSocket.Server use an already existing http server [mmalecki] +* Migrating various option structures to use options.js module [einaros] +* Added a few more tests, options and handshake verifications to ensure that faulty connections are dealt with [einaros] +* Code cleanups in Sender and Receiver, to ensure even faster parsing [einaros] + +v0.3.5 - Dec 13th 2011 +====================== + +* Optimized Sender.js, Receiver.js and bufferutil.cc: + * Apply loop-unrolling-like small block copies rather than use node.js Buffer#copy() (which is slow). + * Mask blocks of data using combination of 32bit xor and loop-unrolling, instead of single bytes. + * Keep pre-made send buffer for small transfers. +* Leak fixes and code cleanups. + +v0.3.3 - Dec 12th 2011 +====================== + +* Compile fix for Linux. +* Rewrote parts of WebSocket.js, to avoid try/catch and thus avoid optimizer bailouts. + +v0.3.2 - Dec 11th 2011 +====================== + +* Further performance updates, including the additions of a native BufferUtil module, which deals with several of the cpu intensive WebSocket operations. + +v0.3.1 - Dec 8th 2011 +====================== + +* Service release, fixing broken tests. + +v0.3.0 - Dec 8th 2011 +====================== + +* Node.js v0.4.x compatibility. +* Code cleanups and efficiency improvements. +* WebSocket server added, although this will still mainly be a client library. +* WebSocket server certified to pass the Autobahn test suite. +* Protocol improvements and corrections - such as handling (redundant) masks for empty fragments. +* 'wscat' command line utility added, which can act as either client or server. + +v0.2.6 - Dec 3rd 2011 +====================== + +* Renamed to 'ws'. Big woop, right -- but easy-websocket really just doesn't cut it anymore! + +v0.2.5 - Dec 3rd 2011 +====================== + + * Rewrote much of the WebSocket parser, to ensure high speed for highly fragmented messages. + * Added a BufferPool, as a start to more efficiently deal with allocations for WebSocket connections. More work to come, in that area. + * Updated the Autobahn report, at http://einaros.github.com/easy-websocket, with comparisons against WebSocket-Node 1.0.2 and Chrome 16. + +v0.2.0 - Nov 25th 2011 +====================== + + * Major rework to make sure all the Autobahn test cases pass. Also updated the internal tests to cover more corner cases. + +v0.1.2 - Nov 14th 2011 +====================== + + * Back and forth, back and forth: now settled on keeping the api (event names, methods) closer to the websocket browser api. This will stick now. + * Started keeping this history record. Better late than never, right? diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/Makefile b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/Makefile new file mode 100644 index 00000000..151aa2ba --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/Makefile @@ -0,0 +1,40 @@ +ALL_TESTS = $(shell find test/ -name '*.test.js') +ALL_INTEGRATION = $(shell find test/ -name '*.integration.js') + +all: + node-gyp configure build + +clean: + node-gyp clean + +run-tests: + @./node_modules/.bin/mocha \ + -t 2000 \ + -s 2400 \ + $(TESTFLAGS) \ + $(TESTS) + +run-integrationtests: + @./node_modules/.bin/mocha \ + -t 5000 \ + -s 6000 \ + $(TESTFLAGS) \ + $(TESTS) + +test: + @$(MAKE) NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_PATH=lib TESTS="$(ALL_TESTS)" run-tests + +integrationtest: + @$(MAKE) NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_PATH=lib TESTS="$(ALL_INTEGRATION)" run-integrationtests + +benchmark: + @node bench/sender.benchmark.js + @node bench/parser.benchmark.js + +autobahn: + @NODE_PATH=lib node test/autobahn.js + +autobahn-server: + @NODE_PATH=lib node test/autobahn-server.js + +.PHONY: test diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/README.md b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/README.md new file mode 100644 index 00000000..e6646e76 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/README.md @@ -0,0 +1,171 @@ +[![Build Status](https://secure.travis-ci.org/einaros/ws.png)](http://travis-ci.org/einaros/ws) + +# ws: a node.js websocket library # + +`ws` is a simple to use websocket implementation, up-to-date against RFC-6455, and [probably the fastest WebSocket library for node.js](http://web.archive.org/web/20130314230536/http://hobbycoding.posterous.com/the-fastest-websocket-module-for-nodejs). + +Passes the quite extensive Autobahn test suite. See http://einaros.github.com/ws for the full reports. + +Comes with a command line utility, `wscat`, which can either act as a server (--listen), or client (--connect); Use it to debug simple websocket services. + +## Protocol support ## + +* **Hixie draft 76** (Old and deprecated, but still in use by Safari and Opera. Added to ws version 0.4.2, but server only. Can be disabled by setting the `disableHixie` option to true.) +* **HyBi drafts 07-12** (Use the option `protocolVersion: 8`, or argument `-p 8` for wscat) +* **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`, or argument `-p 13` for wscat) + +_See the echo.websocket.org example below for how to use the `protocolVersion` option._ + +## Usage ## + +### Installing ### + +`npm install ws` + +### Sending and receiving text data ### + +```js +var WebSocket = require('ws'); +var ws = new WebSocket('ws://www.host.com/path'); +ws.on('open', function() { + ws.send('something'); +}); +ws.on('message', function(data, flags) { + // flags.binary will be set if a binary data is received + // flags.masked will be set if the data was masked +}); +``` + +### Sending binary data ### + +```js +var WebSocket = require('ws'); +var ws = new WebSocket('ws://www.host.com/path'); +ws.on('open', function() { + var array = new Float32Array(5); + for (var i = 0; i < array.length; ++i) array[i] = i / 2; + ws.send(array, {binary: true, mask: true}); +}); +``` + +Setting `mask`, as done for the send options above, will cause the data to be masked according to the websocket protocol. The same option applies for text data. + +### Server example ### + +```js +var WebSocketServer = require('ws').Server + , wss = new WebSocketServer({port: 8080}); +wss.on('connection', function(ws) { + ws.on('message', function(message) { + console.log('received: %s', message); + }); + ws.send('something'); +}); +``` + +### Server sending broadcast data ### + +```js +var WebSocketServer = require('ws').Server + , wss = new WebSocketServer({port: 8080}); + +wss.broadcast = function(data) { + for(var i in this.clients) + this.clients[i].send(data); +}; +``` + +### Error handling best practices ### + +```js +// If the WebSocket is closed before the following send is attempted +ws.send('something'); + +// Errors (both immediate and async write errors) can be detected in an optional callback. +// The callback is also the only way of being notified that data has actually been sent. +ws.send('something', function(error) { + // if error is null, the send has been completed, + // otherwise the error object will indicate what failed. +}); + +// Immediate errors can also be handled with try/catch-blocks, but **note** +// that since sends are inherently asynchronous, socket write failures will *not* +// be captured when this technique is used. +try { + ws.send('something'); +} +catch (e) { + // handle error +} +``` + +### echo.websocket.org demo ### + +```js +var WebSocket = require('ws'); +var ws = new WebSocket('ws://echo.websocket.org/', {protocolVersion: 8, origin: 'http://websocket.org'}); +ws.on('open', function() { + console.log('connected'); + ws.send(Date.now().toString(), {mask: true}); +}); +ws.on('close', function() { + console.log('disconnected'); +}); +ws.on('message', function(data, flags) { + console.log('Roundtrip time: ' + (Date.now() - parseInt(data)) + 'ms', flags); + setTimeout(function() { + ws.send(Date.now().toString(), {mask: true}); + }, 500); +}); +``` + +### wscat against echo.websocket.org ### + + $ npm install -g ws + $ wscat -c ws://echo.websocket.org -p 8 + connected (press CTRL+C to quit) + > hi there + < hi there + > are you a happy parrot? + < are you a happy parrot? + +### Other examples ### + +For a full example with a browser client communicating with a ws server, see the examples folder. + +Note that the usage together with Express 3.0 is quite different from Express 2.x. The difference is expressed in the two different serverstats-examples. + +Otherwise, see the test cases. + +### Running the tests ### + +`make test` + +## API Docs ## + +See the doc/ directory for Node.js-like docs for the ws classes. + +## License ## + +(The MIT License) + +Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com> + +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: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +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. diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/parser.benchmark.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/parser.benchmark.js new file mode 100644 index 00000000..ff5f737c --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/parser.benchmark.js @@ -0,0 +1,115 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +/** + * Benchmark dependencies. + */ + +var benchmark = require('benchmark') + , Receiver = require('../').Receiver + , suite = new benchmark.Suite('Receiver'); +require('tinycolor'); +require('./util'); + +/** + * Setup receiver. + */ + +suite.on('start', function () { + receiver = new Receiver(); +}); + +suite.on('cycle', function () { + receiver = new Receiver(); +}); + +/** + * Benchmarks. + */ + +var pingMessage = 'Hello' + , pingPacket1 = getBufferFromHexString('89 ' + (pack(2, 0x80 | pingMessage.length)) + + ' 34 83 a8 68 '+ getHexStringFromBuffer(mask(pingMessage, '34 83 a8 68'))); +suite.add('ping message', function () { + receiver.add(pingPacket1); +}); + +var pingPacket2 = getBufferFromHexString('89 00') +suite.add('ping with no data', function () { + receiver.add(pingPacket2); +}); + +var closePacket = getBufferFromHexString('88 00'); +suite.add('close message', function () { + receiver.add(closePacket); + receiver.endPacket(); +}); + +var maskedTextPacket = getBufferFromHexString('81 93 34 83 a8 68 01 b9 92 52 4f a1 c6 09 59 e6 8a 52 16 e6 cb 00 5b a1 d5'); +suite.add('masked text message', function () { + receiver.add(maskedTextPacket); +}); + +binaryDataPacket = (function() { + var length = 125 + , message = new Buffer(length) + for (var i = 0; i < length; ++i) message[i] = i % 10; + return getBufferFromHexString('82 ' + getHybiLengthAsHexString(length, true) + ' 34 83 a8 68 ' + + getHexStringFromBuffer(mask(message), '34 83 a8 68')); +})(); +suite.add('binary data (125 bytes)', function () { + try { + receiver.add(binaryDataPacket); + + } + catch(e) {console.log(e)} +}); + +binaryDataPacket2 = (function() { + var length = 65535 + , message = new Buffer(length) + for (var i = 0; i < length; ++i) message[i] = i % 10; + return getBufferFromHexString('82 ' + getHybiLengthAsHexString(length, true) + ' 34 83 a8 68 ' + + getHexStringFromBuffer(mask(message), '34 83 a8 68')); +})(); +suite.add('binary data (65535 bytes)', function () { + receiver.add(binaryDataPacket2); +}); + +binaryDataPacket3 = (function() { + var length = 200*1024 + , message = new Buffer(length) + for (var i = 0; i < length; ++i) message[i] = i % 10; + return getBufferFromHexString('82 ' + getHybiLengthAsHexString(length, true) + ' 34 83 a8 68 ' + + getHexStringFromBuffer(mask(message), '34 83 a8 68')); +})(); +suite.add('binary data (200 kB)', function () { + receiver.add(binaryDataPacket3); +}); + +/** + * Output progress. + */ + +suite.on('cycle', function (bench, details) { + console.log('\n ' + suite.name.grey, details.name.white.bold); + console.log(' ' + [ + details.hz.toFixed(2).cyan + ' ops/sec'.grey + , details.count.toString().white + ' times executed'.grey + , 'benchmark took '.grey + details.times.elapsed.toString().white + ' sec.'.grey + , + ].join(', '.grey)); +}); + +/** + * Run/export benchmarks. + */ + +if (!module.parent) { + suite.run(); +} else { + module.exports = suite; +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/sender.benchmark.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/sender.benchmark.js new file mode 100644 index 00000000..20c171a5 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/sender.benchmark.js @@ -0,0 +1,66 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +/** + * Benchmark dependencies. + */ + +var benchmark = require('benchmark') + , Sender = require('../').Sender + , suite = new benchmark.Suite('Sender'); +require('tinycolor'); +require('./util'); + +/** + * Setup sender. + */ + +suite.on('start', function () { + sender = new Sender(); + sender._socket = { write: function() {} }; +}); + +suite.on('cycle', function () { + sender = new Sender(); + sender._socket = { write: function() {} }; +}); + +/** + * Benchmarks + */ + +framePacket = new Buffer(200*1024); +framePacket.fill(99); +suite.add('frameAndSend, unmasked (200 kB)', function () { + sender.frameAndSend(0x2, framePacket, true, false); +}); +suite.add('frameAndSend, masked (200 kB)', function () { + sender.frameAndSend(0x2, framePacket, true, true); +}); + +/** + * Output progress. + */ + +suite.on('cycle', function (bench, details) { + console.log('\n ' + suite.name.grey, details.name.white.bold); + console.log(' ' + [ + details.hz.toFixed(2).cyan + ' ops/sec'.grey + , details.count.toString().white + ' times executed'.grey + , 'benchmark took '.grey + details.times.elapsed.toString().white + ' sec.'.grey + , + ].join(', '.grey)); +}); + +/** + * Run/export benchmarks. + */ + +if (!module.parent) { + suite.run(); +} else { + module.exports = suite; +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/speed.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/speed.js new file mode 100644 index 00000000..3ce64146 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/speed.js @@ -0,0 +1,105 @@ +var cluster = require('cluster') + , WebSocket = require('../') + , WebSocketServer = WebSocket.Server + , crypto = require('crypto') + , util = require('util') + , ansi = require('ansi'); +require('tinycolor'); + +function roundPrec(num, prec) { + var mul = Math.pow(10, prec); + return Math.round(num * mul) / mul; +} + +function humanSize(bytes) { + if (bytes >= 1048576) return roundPrec(bytes / 1048576, 2) + ' MB'; + if (bytes >= 1024) return roundPrec(bytes / 1024, 2) + ' kB'; + return roundPrec(bytes, 2) + ' B'; +} + +function generateRandomData(size) { + var buffer = new Buffer(size); + for (var i = 0; i < size; ++i) { + buffer[i] = ~~(Math.random() * 127); + } + return buffer; +} + +if (cluster.isMaster) { + var wss = new WebSocketServer({port: 8181}, function() { + cluster.fork(); + }); + wss.on('connection', function(ws) { + ws.on('message', function(data, flags) { + ws.send(data, {binary: flags&&flags.binary}); + }); + ws.on('close', function() {}); + }); + cluster.on('death', function(worker) { + wss.close(); + }); +} +else { + var cursor = ansi(process.stdout); + + var configs = [ + [true, 10000, 64], + [true, 5000, 16*1024], + [true, 1000, 128*1024], + [true, 100, 1024*1024], + [true, 1, 500*1024*1024], + [false, 10000, 64], + [false, 5000, 16*1024], + [false, 1000, 128*1024], + [false, 100, 1024*1024], + ]; + + var largest = configs[0][1]; + for (var i = 0, l = configs.length; i < l; ++i) { + if (configs[i][2] > largest) largest = configs[i][2]; + } + + console.log('Generating %s of test data ...', humanSize(largest)); + var randomBytes = generateRandomData(largest); + + function roundtrip(useBinary, roundtrips, size, cb) { + var data = randomBytes.slice(0, size); + var prefix = util.format('Running %d roundtrips of %s %s data', roundtrips, humanSize(size), useBinary ? 'binary' : 'text'); + console.log(prefix); + var client = new WebSocket('ws://localhost:' + '8181'); + var dt; + var roundtrip = 0; + function send() { + client.send(data, {binary: useBinary}); + } + client.on('error', function(e) { + console.error(e); + process.exit(); + }); + client.on('open', function() { + dt = Date.now(); + send(); + }); + client.on('message', function(data, flags) { + if (++roundtrip == roundtrips) { + var elapsed = Date.now() - dt; + cursor.up(); + console.log('%s:\t%ss\t%s' + , useBinary ? prefix.green : prefix.cyan + , roundPrec(elapsed / 1000, 1).toString().green.bold + , (humanSize((size * roundtrips) / elapsed * 1000) + '/s').blue.bold); + client.close(); + cb(); + return; + } + process.nextTick(send); + }); + } + + (function run() { + if (configs.length == 0) process.exit(); + var config = configs.shift(); + config.push(run); + roundtrip.apply(null, config); + })(); +} \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/util.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/util.js new file mode 100644 index 00000000..5f012819 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/util.js @@ -0,0 +1,105 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +/** + * Returns a Buffer from a "ff 00 ff"-type hex string. + */ + +getBufferFromHexString = function(byteStr) { + var bytes = byteStr.split(' '); + var buf = new Buffer(bytes.length); + for (var i = 0; i < bytes.length; ++i) { + buf[i] = parseInt(bytes[i], 16); + } + return buf; +} + +/** + * Returns a hex string from a Buffer. + */ + +getHexStringFromBuffer = function(data) { + var s = ''; + for (var i = 0; i < data.length; ++i) { + s += padl(data[i].toString(16), 2, '0') + ' '; + } + return s.trim(); +} + +/** + * Splits a buffer in two parts. + */ + +splitBuffer = function(buffer) { + var b1 = new Buffer(Math.ceil(buffer.length / 2)); + buffer.copy(b1, 0, 0, b1.length); + var b2 = new Buffer(Math.floor(buffer.length / 2)); + buffer.copy(b2, 0, b1.length, b1.length + b2.length); + return [b1, b2]; +} + +/** + * Performs hybi07+ type masking on a hex string or buffer. + */ + +mask = function(buf, maskString) { + if (typeof buf == 'string') buf = new Buffer(buf); + var mask = getBufferFromHexString(maskString || '34 83 a8 68'); + for (var i = 0; i < buf.length; ++i) { + buf[i] ^= mask[i % 4]; + } + return buf; +} + +/** + * Returns a hex string representing the length of a message + */ + +getHybiLengthAsHexString = function(len, masked) { + if (len < 126) { + var buf = new Buffer(1); + buf[0] = (masked ? 0x80 : 0) | len; + } + else if (len < 65536) { + var buf = new Buffer(3); + buf[0] = (masked ? 0x80 : 0) | 126; + getBufferFromHexString(pack(4, len)).copy(buf, 1); + } + else { + var buf = new Buffer(9); + buf[0] = (masked ? 0x80 : 0) | 127; + getBufferFromHexString(pack(16, len)).copy(buf, 1); + } + return getHexStringFromBuffer(buf); +} + +/** + * Unpacks a Buffer into a number. + */ + +unpack = function(buffer) { + var n = 0; + for (var i = 0; i < buffer.length; ++i) { + n = (i == 0) ? buffer[i] : (n * 256) + buffer[i]; + } + return n; +} + +/** + * Returns a hex string, representing a specific byte count 'length', from a number. + */ + +pack = function(length, number) { + return padl(number.toString(16), length, '0').replace(/([0-9a-f][0-9a-f])/gi, '$1 ').trim(); +} + +/** + * Left pads the string 's' to a total length of 'n' with char 'c'. + */ + +padl = function(s, n, c) { + return new Array(1 + n - s.length).join(c) + s; +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bin/wscat b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bin/wscat new file mode 100755 index 00000000..0ec894df --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bin/wscat @@ -0,0 +1,190 @@ +#!/usr/bin/env node + +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var WebSocket = require('../') + , fs = require('fs') + , program = require('commander') + , util = require('util') + , events = require('events') + , readline = require('readline'); + +/** + * InputReader - processes console input + */ + +function Console() { + this.stdin = process.stdin; + this.stdout = process.stdout; + + this.readlineInterface = readline.createInterface(this.stdin, this.stdout); + + var self = this; + this.readlineInterface.on('line', function(data) { + self.emit('line', data); + }); + this.readlineInterface.on('close', function() { + self.emit('close'); + }); + + this._resetInput = function() { + self.clear(); + } +} +util.inherits(Console, events.EventEmitter); + +Console.Colors = { + Red: '\033[31m', + Green: '\033[32m', + Yellow: '\033[33m', + Blue: '\033[34m', + Default: '\033[39m' +}; + +Console.prototype.prompt = function() { + this.readlineInterface.prompt(); +} + +Console.prototype.print = function(msg, color) { + this.clear(); + color = color || Console.Colors.Default; + this.stdout.write(color + msg + Console.Colors.Default + '\n'); + this.prompt(); +} + +Console.prototype.clear = function() { + this.stdout.write('\033[2K\033[E'); +} + +Console.prototype.pause = function() { + this.stdin.on('keypress', this._resetInput); +} + +Console.prototype.resume = function() { + this.stdin.removeListener('keypress', this._resetInput); +} + +/** + * The actual application + */ + +var version = JSON.parse(fs.readFileSync(__dirname + '/../package.json', 'utf8')).version; +program + .version(version) + .usage('[options] ') + .option('-l, --listen ', 'listen on port') + .option('-c, --connect ', 'connect to a websocket server') + .option('-p, --protocol ', 'optional protocol version') + .option('-o, --origin ', 'optional origin') + .option('--host ', 'optional host') + .option('-s, --subprotocol ', 'optional subprotocol') + .parse(process.argv); + +if (program.listen && program.connect) { + console.error('\033[33merror: use either --listen or --connect\033[39m'); + process.exit(-1); +} +else if (program.listen) { + var wsConsole = new Console(); + wsConsole.pause(); + var options = {}; + if (program.protocol) options.protocolVersion = program.protocol; + if (program.origin) options.origin = program.origin; + if (program.subprotocol) options.protocol = program.subprotocol; + var ws = null; + var wss = new WebSocket.Server({port: program.listen}, function() { + wsConsole.print('listening on port ' + program.listen + ' (press CTRL+C to quit)', Console.Colors.Green); + wsConsole.clear(); + }); + wsConsole.on('close', function() { + if (ws) { + try { + ws.close(); + } + catch (e) {} + } + process.exit(0); + }); + wsConsole.on('line', function(data) { + if (ws) { + ws.send(data, {mask: false}); + wsConsole.prompt(); + } + }); + wss.on('connection', function(newClient) { + if (ws) { + // limit to one client + newClient.terminate(); + return; + }; + ws = newClient; + wsConsole.resume(); + wsConsole.prompt(); + wsConsole.print('client connected', Console.Colors.Green); + ws.on('close', function() { + wsConsole.print('disconnected', Console.Colors.Green); + wsConsole.clear(); + wsConsole.pause(); + ws = null; + }); + ws.on('error', function(code, description) { + wsConsole.print('error: ' + code + (description ? ' ' + description : ''), Console.Colors.Yellow); + }); + ws.on('message', function(data, flags) { + wsConsole.print('< ' + data, Console.Colors.Blue); + }); + }); + wss.on('error', function(error) { + wsConsole.print('error: ' + error.toString(), Console.Colors.Yellow); + process.exit(-1); + }); +} +else if (program.connect) { + var wsConsole = new Console(); + var options = {}; + if (program.protocol) options.protocolVersion = program.protocol; + if (program.origin) options.origin = program.origin; + if (program.subprotocol) options.protocol = program.subprotocol; + if (program.host) options.host = program.host; + var ws = new WebSocket(program.connect, options); + ws.on('open', function() { + wsConsole.print('connected (press CTRL+C to quit)', Console.Colors.Green); + wsConsole.on('line', function(data) { + ws.send(data, {mask: true}); + wsConsole.prompt(); + }); + }); + ws.on('close', function() { + wsConsole.print('disconnected', Console.Colors.Green); + wsConsole.clear(); + process.exit(); + }); + ws.on('error', function(code, description) { + wsConsole.print('error: ' + code + (description ? ' ' + description : ''), Console.Colors.Yellow); + process.exit(-1); + }); + ws.on('message', function(data, flags) { + wsConsole.print('< ' + data, Console.Colors.Blue); + }); + wsConsole.on('close', function() { + if (ws) { + try { + ws.close(); + } + catch(e) {} + process.exit(); + } + }); +} +else { + console.error('\033[33merror: use either --listen or --connect\033[39m'); + process.exit(-1); +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/binding.gyp b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/binding.gyp new file mode 100644 index 00000000..c9b4d1a4 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/binding.gyp @@ -0,0 +1,16 @@ +{ + 'targets': [ + { + 'target_name': 'validation', + 'include_dirs': ["> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef + +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_objc = CXX($(TOOLSET)) $@ +cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< + +quiet_cmd_objcxx = CXX($(TOOLSET)) $@ +cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# Commands for precompiled header files. +quiet_cmd_pch_c = CXX($(TOOLSET)) $@ +cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ +cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_m = CXX($(TOOLSET)) $@ +cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< +quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ +cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# gyp-mac-tool is written next to the root Makefile by gyp. +# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd +# already. +quiet_cmd_mac_tool = MACTOOL $(4) $< +cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@" + +quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ +cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) + +quiet_cmd_infoplist = INFOPLIST $@ +cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" + +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = rm -rf "$@" && cp -af "$<" "$@" + +quiet_cmd_alink = LIBTOOL-STATIC $@ +cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) + +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +# TODO(thakis): Find out and document the difference between shared_library and +# loadable_module on mac. +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +# TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass +# -bundle -single_module here (for osmesa.so). +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) + + +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' + +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain ? instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\ + for p in $(POSTBUILDS); do\ + eval $$p;\ + E=$$?;\ + if [ $$E -ne 0 ]; then\ + break;\ + fi;\ + done;\ + if [ $$E -ne 0 ]; then\ + rm -rf "$@";\ + exit $$E;\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for +# spaces already and dirx strips the ? characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word 2,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "all" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: all +all: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +TOOLSET := target +# Suffix rules, putting all outputs into $(obj). +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + + +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,bufferutil.target.mk)))),) + include bufferutil.target.mk +endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,validation.target.mk)))),) + include validation.target.mk +endif + +quiet_cmd_regen_makefile = ACTION Regenerating $@ +cmd_regen_makefile = /usr/local/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -I/Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/config.gypi -I/usr/local/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/izhukov/.node-gyp/0.10.22/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/izhukov/.node-gyp/0.10.22" "-Dmodule_root_dir=/Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws" binding.gyp +Makefile: $(srcdir)/../../../../../../../../../../.node-gyp/0.10.22/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../../../../../../../../usr/local/lib/node_modules/npm/node_modules/node-gyp/addon.gypi + $(call do_cmd,regen_makefile) + +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/bufferutil.node.d b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/bufferutil.node.d new file mode 100644 index 00000000..8b191311 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/bufferutil.node.d @@ -0,0 +1 @@ +cmd_Release/bufferutil.node := ./gyp-mac-tool flock ./Release/linker.lock c++ -shared -Wl,-search_paths_first -mmacosx-version-min=10.5 -arch x86_64 -L./Release -install_name @rpath/bufferutil.node -o Release/bufferutil.node Release/obj.target/bufferutil/src/bufferutil.o -undefined dynamic_lookup diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d new file mode 100644 index 00000000..96b92036 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d @@ -0,0 +1,23 @@ +cmd_Release/obj.target/bufferutil/src/bufferutil.o := c++ '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/Users/izhukov/.node-gyp/0.10.22/src -I/Users/izhukov/.node-gyp/0.10.22/deps/uv/include -I/Users/izhukov/.node-gyp/0.10.22/deps/v8/include -I/Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d.raw -c -o Release/obj.target/bufferutil/src/bufferutil.o ../src/bufferutil.cc +Release/obj.target/bufferutil/src/bufferutil.o: ../src/bufferutil.cc \ + /Users/izhukov/.node-gyp/0.10.22/deps/v8/include/v8.h \ + /Users/izhukov/.node-gyp/0.10.22/deps/v8/include/v8stdint.h \ + /Users/izhukov/.node-gyp/0.10.22/src/node.h \ + /Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv.h \ + /Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/uv-unix.h \ + /Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/ngx-queue.h \ + /Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/uv-darwin.h \ + /Users/izhukov/.node-gyp/0.10.22/src/node_object_wrap.h \ + /Users/izhukov/.node-gyp/0.10.22/src/node_buffer.h \ + /Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/nan.h +../src/bufferutil.cc: +/Users/izhukov/.node-gyp/0.10.22/deps/v8/include/v8.h: +/Users/izhukov/.node-gyp/0.10.22/deps/v8/include/v8stdint.h: +/Users/izhukov/.node-gyp/0.10.22/src/node.h: +/Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv.h: +/Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/uv-unix.h: +/Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/ngx-queue.h: +/Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/uv-darwin.h: +/Users/izhukov/.node-gyp/0.10.22/src/node_object_wrap.h: +/Users/izhukov/.node-gyp/0.10.22/src/node_buffer.h: +/Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/nan.h: diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/obj.target/validation/src/validation.o.d b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/obj.target/validation/src/validation.o.d new file mode 100644 index 00000000..e327f957 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/obj.target/validation/src/validation.o.d @@ -0,0 +1,23 @@ +cmd_Release/obj.target/validation/src/validation.o := c++ '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/Users/izhukov/.node-gyp/0.10.22/src -I/Users/izhukov/.node-gyp/0.10.22/deps/uv/include -I/Users/izhukov/.node-gyp/0.10.22/deps/v8/include -I/Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/validation/src/validation.o.d.raw -c -o Release/obj.target/validation/src/validation.o ../src/validation.cc +Release/obj.target/validation/src/validation.o: ../src/validation.cc \ + /Users/izhukov/.node-gyp/0.10.22/deps/v8/include/v8.h \ + /Users/izhukov/.node-gyp/0.10.22/deps/v8/include/v8stdint.h \ + /Users/izhukov/.node-gyp/0.10.22/src/node.h \ + /Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv.h \ + /Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/uv-unix.h \ + /Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/ngx-queue.h \ + /Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/uv-darwin.h \ + /Users/izhukov/.node-gyp/0.10.22/src/node_object_wrap.h \ + /Users/izhukov/.node-gyp/0.10.22/src/node_buffer.h \ + /Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/nan.h +../src/validation.cc: +/Users/izhukov/.node-gyp/0.10.22/deps/v8/include/v8.h: +/Users/izhukov/.node-gyp/0.10.22/deps/v8/include/v8stdint.h: +/Users/izhukov/.node-gyp/0.10.22/src/node.h: +/Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv.h: +/Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/uv-unix.h: +/Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/ngx-queue.h: +/Users/izhukov/.node-gyp/0.10.22/deps/uv/include/uv-private/uv-darwin.h: +/Users/izhukov/.node-gyp/0.10.22/src/node_object_wrap.h: +/Users/izhukov/.node-gyp/0.10.22/src/node_buffer.h: +/Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/nan.h: diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/validation.node.d b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/validation.node.d new file mode 100644 index 00000000..869c91e2 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/.deps/Release/validation.node.d @@ -0,0 +1 @@ +cmd_Release/validation.node := ./gyp-mac-tool flock ./Release/linker.lock c++ -shared -Wl,-search_paths_first -mmacosx-version-min=10.5 -arch x86_64 -L./Release -install_name @rpath/validation.node -o Release/validation.node Release/obj.target/validation/src/validation.o -undefined dynamic_lookup diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/bufferutil.node b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/bufferutil.node new file mode 100755 index 00000000..192474d8 Binary files /dev/null and b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/bufferutil.node differ diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/linker.lock b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/linker.lock new file mode 100644 index 00000000..e69de29b diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/obj.target/bufferutil/src/bufferutil.o b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/obj.target/bufferutil/src/bufferutil.o new file mode 100644 index 00000000..c6615bb2 Binary files /dev/null and b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/obj.target/bufferutil/src/bufferutil.o differ diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/obj.target/validation/src/validation.o b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/obj.target/validation/src/validation.o new file mode 100644 index 00000000..62b54ece Binary files /dev/null and b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/obj.target/validation/src/validation.o differ diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/validation.node b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/validation.node new file mode 100755 index 00000000..054cdc48 Binary files /dev/null and b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/Release/validation.node differ diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/binding.Makefile b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/binding.Makefile new file mode 100644 index 00000000..a69b3d2c --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/binding.Makefile @@ -0,0 +1,6 @@ +# This file is generated by gyp; do not edit. + +export builddir_name ?= build/./. +.PHONY: all +all: + $(MAKE) bufferutil validation diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/bufferutil.target.mk b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/bufferutil.target.mk new file mode 100644 index 00000000..9d47e6e9 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/bufferutil.target.mk @@ -0,0 +1,158 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := bufferutil +DEFS_Debug := \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DBUILDING_NODE_EXTENSION' \ + '-DDEBUG' \ + '-D_DEBUG' + +# Flags passed to all source files. +CFLAGS_Debug := \ + -O0 \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Debug := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Debug := \ + -fno-rtti \ + -fno-exceptions \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Debug := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Debug := + +INCS_Debug := \ + -I/Users/izhukov/.node-gyp/0.10.22/src \ + -I/Users/izhukov/.node-gyp/0.10.22/deps/uv/include \ + -I/Users/izhukov/.node-gyp/0.10.22/deps/v8/include \ + -I/Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan + +DEFS_Release := \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DBUILDING_NODE_EXTENSION' + +# Flags passed to all source files. +CFLAGS_Release := \ + -Os \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Release := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Release := \ + -fno-rtti \ + -fno-exceptions \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Release := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Release := + +INCS_Release := \ + -I/Users/izhukov/.node-gyp/0.10.22/src \ + -I/Users/izhukov/.node-gyp/0.10.22/deps/uv/include \ + -I/Users/izhukov/.node-gyp/0.10.22/deps/v8/include \ + -I/Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan + +OBJS := \ + $(obj).target/$(TARGET)/src/bufferutil.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_Debug := \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) \ + -install_name @rpath/bufferutil.node + +LIBTOOLFLAGS_Debug := \ + -Wl,-search_paths_first + +LDFLAGS_Release := \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) \ + -install_name @rpath/bufferutil.node + +LIBTOOLFLAGS_Release := \ + -Wl,-search_paths_first + +LIBS := \ + -undefined dynamic_lookup + +$(builddir)/bufferutil.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/bufferutil.node: LIBS := $(LIBS) +$(builddir)/bufferutil.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE)) +$(builddir)/bufferutil.node: TOOLSET := $(TOOLSET) +$(builddir)/bufferutil.node: $(OBJS) FORCE_DO_CMD + $(call do_cmd,solink_module) + +all_deps += $(builddir)/bufferutil.node +# Add target alias +.PHONY: bufferutil +bufferutil: $(builddir)/bufferutil.node + +# Short alias for building this executable. +.PHONY: bufferutil.node +bufferutil.node: $(builddir)/bufferutil.node + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/bufferutil.node + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/config.gypi b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/config.gypi new file mode 100644 index 00000000..ebe1f41a --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/config.gypi @@ -0,0 +1,112 @@ +# Do not edit. File was generated by node-gyp's "configure" step +{ + "target_defaults": { + "cflags": [], + "default_configuration": "Release", + "defines": [], + "include_dirs": [], + "libraries": [] + }, + "variables": { + "clang": 1, + "host_arch": "x64", + "node_install_npm": "true", + "node_prefix": "", + "node_shared_cares": "false", + "node_shared_http_parser": "false", + "node_shared_libuv": "false", + "node_shared_openssl": "false", + "node_shared_v8": "false", + "node_shared_zlib": "false", + "node_tag": "", + "node_unsafe_optimizations": 0, + "node_use_dtrace": "true", + "node_use_etw": "false", + "node_use_openssl": "true", + "node_use_perfctr": "false", + "python": "/usr/bin/python", + "target_arch": "x64", + "v8_enable_gdbjit": 0, + "v8_no_strict_aliasing": 1, + "v8_use_snapshot": "false", + "nodedir": "/Users/izhukov/.node-gyp/0.10.22", + "copy_dev_lib": "true", + "standalone_static_library": 1, + "save_dev": "true", + "browser": "", + "viewer": "man", + "rollback": "true", + "usage": "", + "globalignorefile": "/usr/local/etc/npmignore", + "init_author_url": "", + "shell": "/bin/bash", + "parseable": "", + "shrinkwrap": "true", + "userignorefile": "/Users/izhukov/.npmignore", + "cache_max": "null", + "init_author_email": "", + "sign_git_tag": "", + "ignore": "", + "long": "", + "registry": "https://registry.npmjs.org/", + "fetch_retries": "2", + "npat": "", + "message": "%s", + "versions": "", + "globalconfig": "/usr/local/etc/npmrc", + "always_auth": "", + "cache_lock_retries": "10", + "fetch_retry_mintimeout": "10000", + "proprietary_attribs": "true", + "coverage": "", + "json": "", + "pre": "", + "description": "true", + "engine_strict": "", + "https_proxy": "", + "init_module": "/Users/izhukov/.npm-init.js", + "userconfig": "/Users/izhukov/.npmrc", + "npaturl": "http://npat.npmjs.org/", + "node_version": "v0.10.22", + "user": "", + "editor": "vi", + "save": "", + "tag": "latest", + "global": "", + "optional": "true", + "username": "", + "bin_links": "true", + "force": "", + "searchopts": "", + "depth": "null", + "rebuild_bundle": "true", + "searchsort": "name", + "unicode": "true", + "yes": "", + "fetch_retry_maxtimeout": "60000", + "strict_ssl": "true", + "dev": "", + "fetch_retry_factor": "10", + "group": "20", + "cache_lock_stale": "60000", + "version": "", + "cache_min": "10", + "cache": "/Users/izhukov/.npm", + "searchexclude": "", + "color": "true", + "save_optional": "", + "user_agent": "node/v0.10.22 darwin x64", + "cache_lock_wait": "10000", + "production": "", + "save_bundle": "", + "init_version": "0.0.0", + "umask": "18", + "git": "git", + "init_author_name": "", + "onload_script": "", + "tmp": "/var/folders/2l/8552b3mn10jdp069ksjlh5000000gn/T/", + "unsafe_perm": "true", + "link": "", + "prefix": "/usr/local" + } +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/gyp-mac-tool b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/gyp-mac-tool new file mode 100755 index 00000000..2f5e141f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/gyp-mac-tool @@ -0,0 +1,224 @@ +#!/usr/bin/env python +# Generated by gyp. Do not edit. +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Utility functions to perform Xcode-style build steps. + +These functions are executed via gyp-mac-tool when using the Makefile generator. +""" + +import fcntl +import os +import plistlib +import re +import shutil +import string +import subprocess +import sys + + +def main(args): + executor = MacTool() + exit_code = executor.Dispatch(args) + if exit_code is not None: + sys.exit(exit_code) + + +class MacTool(object): + """This class performs all the Mac tooling steps. The methods can either be + executed directly, or dispatched from an argument list.""" + + def Dispatch(self, args): + """Dispatches a string command to a method.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + method = "Exec%s" % self._CommandifyName(args[0]) + return getattr(self, method)(*args[1:]) + + def _CommandifyName(self, name_string): + """Transforms a tool name like copy-info-plist to CopyInfoPlist""" + return name_string.title().replace('-', '') + + def ExecCopyBundleResource(self, source, dest): + """Copies a resource file to the bundle/Resources directory, performing any + necessary compilation on each resource.""" + extension = os.path.splitext(source)[1].lower() + if os.path.isdir(source): + # Copy tree. + if os.path.exists(dest): + shutil.rmtree(dest) + shutil.copytree(source, dest) + elif extension == '.xib': + return self._CopyXIBFile(source, dest) + elif extension == '.strings': + self._CopyStringsFile(source, dest) + else: + shutil.copyfile(source, dest) + + def _CopyXIBFile(self, source, dest): + """Compiles a XIB file with ibtool into a binary plist in the bundle.""" + tools_dir = os.environ.get('DEVELOPER_BIN_DIR', '/usr/bin') + args = [os.path.join(tools_dir, 'ibtool'), '--errors', '--warnings', + '--notices', '--output-format', 'human-readable-text', '--compile', + dest, source] + ibtool_section_re = re.compile(r'/\*.*\*/') + ibtool_re = re.compile(r'.*note:.*is clipping its content') + ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE) + current_section_header = None + for line in ibtoolout.stdout: + if ibtool_section_re.match(line): + current_section_header = line + elif not ibtool_re.match(line): + if current_section_header: + sys.stdout.write(current_section_header) + current_section_header = None + sys.stdout.write(line) + return ibtoolout.returncode + + def _CopyStringsFile(self, source, dest): + """Copies a .strings file using iconv to reconvert the input into UTF-16.""" + input_code = self._DetectInputEncoding(source) or "UTF-8" + + # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call + # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints + # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing + # semicolon in dictionary. + # on invalid files. Do the same kind of validation. + import CoreFoundation + s = open(source).read() + d = CoreFoundation.CFDataCreate(None, s, len(s)) + _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None) + if error: + return + + fp = open(dest, 'w') + args = ['/usr/bin/iconv', '--from-code', input_code, '--to-code', + 'UTF-16', source] + subprocess.call(args, stdout=fp) + fp.close() + + def _DetectInputEncoding(self, file_name): + """Reads the first few bytes from file_name and tries to guess the text + encoding. Returns None as a guess if it can't detect it.""" + fp = open(file_name, 'rb') + try: + header = fp.read(3) + except e: + fp.close() + return None + fp.close() + if header.startswith("\xFE\xFF"): + return "UTF-16BE" + elif header.startswith("\xFF\xFE"): + return "UTF-16LE" + elif header.startswith("\xEF\xBB\xBF"): + return "UTF-8" + else: + return None + + def ExecCopyInfoPlist(self, source, dest): + """Copies the |source| Info.plist to the destination directory |dest|.""" + # Read the source Info.plist into memory. + fd = open(source, 'r') + lines = fd.read() + fd.close() + + # Go through all the environment variables and replace them as variables in + # the file. + for key in os.environ: + if key.startswith('_'): + continue + evar = '${%s}' % key + lines = string.replace(lines, evar, os.environ[key]) + + # Write out the file with variables replaced. + fd = open(dest, 'w') + fd.write(lines) + fd.close() + + # Now write out PkgInfo file now that the Info.plist file has been + # "compiled". + self._WritePkgInfo(dest) + + def _WritePkgInfo(self, info_plist): + """This writes the PkgInfo file from the data stored in Info.plist.""" + plist = plistlib.readPlist(info_plist) + if not plist: + return + + # Only create PkgInfo for executable types. + package_type = plist['CFBundlePackageType'] + if package_type != 'APPL': + return + + # The format of PkgInfo is eight characters, representing the bundle type + # and bundle signature, each four characters. If that is missing, four + # '?' characters are used instead. + signature_code = plist.get('CFBundleSignature', '????') + if len(signature_code) != 4: # Wrong length resets everything, too. + signature_code = '?' * 4 + + dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo') + fp = open(dest, 'w') + fp.write('%s%s' % (package_type, signature_code)) + fp.close() + + def ExecFlock(self, lockfile, *cmd_list): + """Emulates the most basic behavior of Linux's flock(1).""" + # Rely on exception handling to report errors. + fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666) + fcntl.flock(fd, fcntl.LOCK_EX) + return subprocess.call(cmd_list) + + def ExecFilterLibtool(self, *cmd_list): + """Calls libtool and filters out 'libtool: file: foo.o has no symbols'.""" + libtool_re = re.compile(r'^libtool: file: .* has no symbols$') + libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE) + _, err = libtoolout.communicate() + for line in err.splitlines(): + if not libtool_re.match(line): + print >>sys.stderr, line + return libtoolout.returncode + + def ExecPackageFramework(self, framework, version): + """Takes a path to Something.framework and the Current version of that and + sets up all the symlinks.""" + # Find the name of the binary based on the part before the ".framework". + binary = os.path.basename(framework).split('.')[0] + + CURRENT = 'Current' + RESOURCES = 'Resources' + VERSIONS = 'Versions' + + if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)): + # Binary-less frameworks don't seem to contain symlinks (see e.g. + # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle). + return + + # Move into the framework directory to set the symlinks correctly. + pwd = os.getcwd() + os.chdir(framework) + + # Set up the Current version. + self._Relink(version, os.path.join(VERSIONS, CURRENT)) + + # Set up the root symlinks. + self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary) + self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES) + + # Back to where we were before! + os.chdir(pwd) + + def _Relink(self, dest, link): + """Creates a symlink to |dest| named |link|. If |link| already exists, + it is overwritten.""" + if os.path.lexists(link): + os.remove(link) + os.symlink(dest, link) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/validation.target.mk b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/validation.target.mk new file mode 100644 index 00000000..13ecfeba --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/build/validation.target.mk @@ -0,0 +1,158 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := validation +DEFS_Debug := \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DBUILDING_NODE_EXTENSION' \ + '-DDEBUG' \ + '-D_DEBUG' + +# Flags passed to all source files. +CFLAGS_Debug := \ + -O0 \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Debug := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Debug := \ + -fno-rtti \ + -fno-exceptions \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Debug := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Debug := + +INCS_Debug := \ + -I/Users/izhukov/.node-gyp/0.10.22/src \ + -I/Users/izhukov/.node-gyp/0.10.22/deps/uv/include \ + -I/Users/izhukov/.node-gyp/0.10.22/deps/v8/include \ + -I/Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan + +DEFS_Release := \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DBUILDING_NODE_EXTENSION' + +# Flags passed to all source files. +CFLAGS_Release := \ + -Os \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Release := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Release := \ + -fno-rtti \ + -fno-exceptions \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Release := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Release := + +INCS_Release := \ + -I/Users/izhukov/.node-gyp/0.10.22/src \ + -I/Users/izhukov/.node-gyp/0.10.22/deps/uv/include \ + -I/Users/izhukov/.node-gyp/0.10.22/deps/v8/include \ + -I/Users/izhukov/Documents/webogram/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan + +OBJS := \ + $(obj).target/$(TARGET)/src/validation.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_Debug := \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) \ + -install_name @rpath/validation.node + +LIBTOOLFLAGS_Debug := \ + -Wl,-search_paths_first + +LDFLAGS_Release := \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) \ + -install_name @rpath/validation.node + +LIBTOOLFLAGS_Release := \ + -Wl,-search_paths_first + +LIBS := \ + -undefined dynamic_lookup + +$(builddir)/validation.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/validation.node: LIBS := $(LIBS) +$(builddir)/validation.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE)) +$(builddir)/validation.node: TOOLSET := $(TOOLSET) +$(builddir)/validation.node: $(OBJS) FORCE_DO_CMD + $(call do_cmd,solink_module) + +all_deps += $(builddir)/validation.node +# Add target alias +.PHONY: validation +validation: $(builddir)/validation.node + +# Short alias for building this executable. +.PHONY: validation.node +validation.node: $(builddir)/validation.node + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/validation.node + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/builderror.log b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/builderror.log new file mode 100644 index 00000000..d493584f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/builderror.log @@ -0,0 +1,2 @@ +gyp http GET http://nodejs.org/dist/v0.10.22/node-v0.10.22.tar.gz +gyp http 200 http://nodejs.org/dist/v0.10.22/node-v0.10.22.tar.gz diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/doc/ws.md b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/doc/ws.md new file mode 100644 index 00000000..d84fd625 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/doc/ws.md @@ -0,0 +1,181 @@ +# ws + +## Class: ws.Server + +This class is a WebSocket server. It is an `EventEmitter`. + +### new ws.Server([options], [callback]) + +* `options` Object + * `host` String + * `port` Number + * `server` http.Server + * `verifyClient` Function + * `path` String + * `noServer` Boolean + * `disableHixie` Boolean + * `clientTracking` Boolean +* `callback` Function + +Construct a new server object. + +Either `port` or `server` must be provided, otherwise you might enable +`noServer` if you want to pass the requests directly. Please note that the +`callback` is only used when you supply the a `port` number in the options. + +### server.close([code], [data]) + +Close the server and terminate all clients + +### server.handleUpgrade(request, socket, upgradeHead, callback) + +Handles a HTTP Upgrade request. `request` is an instance of `http.ServerRequest`, `socket` is an instance of `net.Socket`. + +When the Upgrade was successfully, the `callback` will be called with a `ws.WebSocket` object as parameter. + +### Event: 'error' + +`function (error) { }` + +If the underlying server emits an error, it will be forwarded here. + +### Event: 'headers' + +`function (headers) { }` + +Emitted with the object of HTTP headers that are going to be written to the `Stream` as part of the handshake. + +### Event: 'connection' + +`function (socket) { }` + +When a new WebSocket connection is established. `socket` is an object of type `ws.WebSocket`. + + +## Class: ws.WebSocket + +This class represents a WebSocket connection. It is an `EventEmitter`. + +### new ws.WebSocket(address, [options]) + +* `address` String|Array +* `options` Object + * `protocol` String + * `agent` Agent + * `headers` Object + * `protocolVersion` Number|String + -- the following only apply if `address` is a String + * `host` String + * `origin` String + * `pfx` String|Buffer + * `key` String|Buffer + * `passphrase` String + * `cert` String|Buffer + * `ca` Array + * `ciphers` String + * `rejectUnauthorized` Boolean + +Instantiating with an `address` creates a new WebSocket client object. If `address` is an Array (request, socket, rest), it is instantiated as a Server client (e.g. called from the `ws.Server`). + +### websocket.bytesReceived + +Received bytes count. + +### websocket.readyState + +Possible states are `WebSocket.CONNECTING`, `WebSocket.OPEN`, `WebSocket.CLOSING`, `WebSocket.CLOSED`. + +### websocket.protocolVersion + +The WebSocket protocol version used for this connection, `8`, `13` or `hixie-76` (the latter only for server clients). + +### websocket.url + +The URL of the WebSocket server (only for clients) + +### websocket.supports + +Describes the feature of the used protocol version. E.g. `supports.binary` is a boolean that describes if the connection supports binary messages. + +### websocket.close([code], [data]) + +Gracefully closes the connection, after sending a description message + +### websocket.pause() + +Pause the client stream + +### websocket.ping([data], [options], [dontFailWhenClosed]) + +Sends a ping. `data` is sent, `options` is an object with members `mask` and `binary`. `dontFailWhenClosed` indicates whether or not to throw if the connection isnt open. + +### websocket.pong([data], [options], [dontFailWhenClosed]) + +Sends a pong. `data` is sent, `options` is an object with members `mask` and `binary`. `dontFailWhenClosed` indicates whether or not to throw if the connection isnt open. + + +### websocket.resume() + +Resume the client stream + +### websocket.send(data, [options], [callback]) + +Sends `data` through the connection. `options` can be an object with members `mask` and `binary`. The optional `callback` is executed after the send completes. + +### websocket.stream([options], callback) + +Streams data through calls to a user supplied function. `options` can be an object with members `mask` and `binary`. `callback` is executed on successive ticks of which send is `function (data, final)`. + +### websocket.terminate() + +Immediately shuts down the connection + +### websocket.onopen +### websocket.onerror +### websocket.onclose +### websocket.onmessage + +Emulates the W3C Browser based WebSocket interface using function members. + +### websocket.addEventListener(method, listener) + +Emulates the W3C Browser based WebSocket interface using addEventListener. + +### Event: 'error' + +`function (error) { }` + +If the client emits an error, this event is emitted (errors from the underlying `net.Socket` are forwarded here). + +### Event: 'close' + +`function (code, message) { }` + +Is emitted when the connection is closed. `code` is defined in the WebSocket specification. + +The `close` event is also emitted when then underlying `net.Socket` closes the connection (`end` or `close`). + +### Event: 'message' + +`function (data, flags) { }` + +Is emitted when data is received. `flags` is an object with member `binary`. + +### Event: 'ping' + +`function (data, flags) { }` + +Is emitted when a ping is received. `flags` is an object with member `binary`. + +### Event: 'pong' + +`function (data, flags) { }` + +Is emitted when a pong is received. `flags` is an object with member `binary`. + +### Event: 'open' + +`function () { }` + +Emitted when the connection is established. + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/.npmignore b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/.npmignore new file mode 100644 index 00000000..dcd57568 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/.npmignore @@ -0,0 +1 @@ +uploaded diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/package.json new file mode 100644 index 00000000..7816f273 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/package.json @@ -0,0 +1,18 @@ +{ + "author": "", + "name": "fileapi", + "version": "0.0.0", + "repository": { + "type": "git", + "url": "git://github.com/einaros/ws.git" + }, + "engines": { + "node": "~0.6.8" + }, + "dependencies": { + "express": "latest", + "ansi": "https://github.com/einaros/ansi.js/tarball/master" + }, + "devDependencies": {}, + "optionalDependencies": {} +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/app.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/app.js new file mode 100644 index 00000000..e812cc3e --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/app.js @@ -0,0 +1,39 @@ +function onFilesSelected(e) { + var button = e.srcElement; + button.disabled = true; + var progress = document.querySelector('div#progress'); + progress.innerHTML = '0%'; + var files = e.target.files; + var totalFiles = files.length; + var filesSent = 0; + if (totalFiles) { + var uploader = new Uploader('ws://localhost:8080', function () { + Array.prototype.slice.call(files, 0).forEach(function(file) { + if (file.name == '.') { + --totalFiles; + return; + } + uploader.sendFile(file, function(error) { + if (error) { + console.log(error); + return; + } + ++filesSent; + progress.innerHTML = ~~(filesSent / totalFiles * 100) + '%'; + console.log('Sent: ' + file.name); + }); + }); + }); + } + uploader.ondone = function() { + uploader.close(); + progress.innerHTML = '100% done, ' + totalFiles + ' files sent.'; + } +} + +window.onload = function() { + var importButtons = document.querySelectorAll('[type="file"]'); + Array.prototype.slice.call(importButtons, 0).forEach(function(importButton) { + importButton.addEventListener('change', onFilesSelected, false); + }); +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/index.html b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/index.html new file mode 100644 index 00000000..0d463dd5 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/index.html @@ -0,0 +1,22 @@ + + + + + + + + +

    This example will upload an entire directory tree to the node.js server via a fast and persistent WebSocket connection.

    +

    Note that the example is Chrome only for now.

    +

    + Upload status: +
    Please select a directory to upload.
    + + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/uploader.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/uploader.js new file mode 100644 index 00000000..0c34a7fa --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/uploader.js @@ -0,0 +1,55 @@ +function Uploader(url, cb) { + this.ws = new WebSocket(url); + if (cb) this.ws.onopen = cb; + this.sendQueue = []; + this.sending = null; + this.sendCallback = null; + this.ondone = null; + var self = this; + this.ws.onmessage = function(event) { + var data = JSON.parse(event.data); + if (data.event == 'complete') { + if (data.path != self.sending.path) { + self.sendQueue = []; + self.sending = null; + self.sendCallback = null; + throw new Error('Got message for wrong file!'); + } + self.sending = null; + var callback = self.sendCallback; + self.sendCallback = null; + if (callback) callback(); + if (self.sendQueue.length === 0 && self.ondone) self.ondone(null); + if (self.sendQueue.length > 0) { + var args = self.sendQueue.pop(); + setTimeout(function() { self.sendFile.apply(self, args); }, 0); + } + } + else if (data.event == 'error') { + self.sendQueue = []; + self.sending = null; + var callback = self.sendCallback; + self.sendCallback = null; + var error = new Error('Server reported send error for file ' + data.path); + if (callback) callback(error); + if (self.ondone) self.ondone(error); + } + } +} + +Uploader.prototype.sendFile = function(file, cb) { + if (this.ws.readyState != WebSocket.OPEN) throw new Error('Not connected'); + if (this.sending) { + this.sendQueue.push(arguments); + return; + } + var fileData = { name: file.name, path: file.webkitRelativePath }; + this.sending = fileData; + this.sendCallback = cb; + this.ws.send(JSON.stringify(fileData)); + this.ws.send(file); +} + +Uploader.prototype.close = function() { + this.ws.close(); +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/server.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/server.js new file mode 100644 index 00000000..badfeba7 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/server.js @@ -0,0 +1,103 @@ +var WebSocketServer = require('../../').Server + , express = require('express') + , fs = require('fs') + , http = require('http') + , util = require('util') + , path = require('path') + , app = express.createServer() + , events = require('events') + , ansi = require('ansi') + , cursor = ansi(process.stdout); + +function BandwidthSampler(ws, interval) { + interval = interval || 2000; + var previousByteCount = 0; + var self = this; + var intervalId = setInterval(function() { + var byteCount = ws.bytesReceived; + var bytesPerSec = (byteCount - previousByteCount) / (interval / 1000); + previousByteCount = byteCount; + self.emit('sample', bytesPerSec); + }, interval); + ws.on('close', function() { + clearInterval(intervalId); + }); +} +util.inherits(BandwidthSampler, events.EventEmitter); + +function makePathForFile(filePath, prefix, cb) { + if (typeof cb !== 'function') throw new Error('callback is required'); + filePath = path.dirname(path.normalize(filePath)).replace(/^(\/|\\)+/, ''); + var pieces = filePath.split(/(\\|\/)/); + var incrementalPath = prefix; + function step(error) { + if (error) return cb(error); + if (pieces.length == 0) return cb(null, incrementalPath); + incrementalPath += '/' + pieces.shift(); + fs.exists(incrementalPath, function(exists) { + if (!exists) fs.mkdir(incrementalPath, step); + else process.nextTick(step); + }); + } + step(); +} + +cursor.eraseData(2).goto(1, 1); +app.use(express.static(__dirname + '/public')); + +var clientId = 0; +var wss = new WebSocketServer({server: app}); +wss.on('connection', function(ws) { + var thisId = ++clientId; + cursor.goto(1, 4 + thisId).eraseLine(); + console.log('Client #%d connected', thisId); + + var sampler = new BandwidthSampler(ws); + sampler.on('sample', function(bps) { + cursor.goto(1, 4 + thisId).eraseLine(); + console.log('WebSocket #%d incoming bandwidth: %d MB/s', thisId, Math.round(bps / (1024*1024))); + }); + + var filesReceived = 0; + var currentFile = null; + ws.on('message', function(data, flags) { + if (!flags.binary) { + currentFile = JSON.parse(data); + // note: a real-world app would want to sanity check the data + } + else { + if (currentFile == null) return; + makePathForFile(currentFile.path, __dirname + '/uploaded', function(error, path) { + if (error) { + console.log(error); + ws.send(JSON.stringify({event: 'error', path: currentFile.path, message: error.message})); + return; + } + fs.writeFile(path + '/' + currentFile.name, data, function(error) { + ++filesReceived; + // console.log('received %d bytes long file, %s', data.length, currentFile.path); + ws.send(JSON.stringify({event: 'complete', path: currentFile.path})); + currentFile = null; + }); + }); + } + }); + + ws.on('close', function() { + cursor.goto(1, 4 + thisId).eraseLine(); + console.log('Client #%d disconnected. %d files received.', thisId, filesReceived); + }); + + ws.on('error', function(e) { + cursor.goto(1, 4 + thisId).eraseLine(); + console.log('Client #%d error: %s', thisId, e.message); + }); +}); + +fs.mkdir(__dirname + '/uploaded', function(error) { + // ignore errors, most likely means directory exists + console.log('Uploaded files will be saved to %s/uploaded.', __dirname); + console.log('Remember to wipe this directory if you upload lots and lots.'); + app.listen(8080); + console.log('Listening on http://localhost:8080'); +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/package.json new file mode 100644 index 00000000..99722c42 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/package.json @@ -0,0 +1,17 @@ +{ + "author": "", + "name": "serverstats", + "version": "0.0.0", + "repository": { + "type": "git", + "url": "git://github.com/einaros/ws.git" + }, + "engines": { + "node": ">0.4.0" + }, + "dependencies": { + "express": "~3.0.0" + }, + "devDependencies": {}, + "optionalDependencies": {} +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/public/index.html b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/public/index.html new file mode 100644 index 00000000..24d84e12 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/public/index.html @@ -0,0 +1,33 @@ + + + + + + + + Server Stats
    + RSS:

    + Heap total:

    + Heap used:

    + + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/server.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/server.js new file mode 100644 index 00000000..88bbc9eb --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/server.js @@ -0,0 +1,21 @@ +var WebSocketServer = require('../../').Server + , http = require('http') + , express = require('express') + , app = express(); + +app.use(express.static(__dirname + '/public')); + +var server = http.createServer(app); +server.listen(8080); + +var wss = new WebSocketServer({server: server}); +wss.on('connection', function(ws) { + var id = setInterval(function() { + ws.send(JSON.stringify(process.memoryUsage()), function() { /* ignore errors */ }); + }, 100); + console.log('started client interval'); + ws.on('close', function() { + console.log('stopping client interval'); + clearInterval(id); + }); +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/package.json new file mode 100644 index 00000000..65c900ab --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/package.json @@ -0,0 +1,17 @@ +{ + "author": "", + "name": "serverstats", + "version": "0.0.0", + "repository": { + "type": "git", + "url": "git://github.com/einaros/ws.git" + }, + "engines": { + "node": ">0.4.0" + }, + "dependencies": { + "express": "2.x" + }, + "devDependencies": {}, + "optionalDependencies": {} +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/public/index.html b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/public/index.html new file mode 100644 index 00000000..24d84e12 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/public/index.html @@ -0,0 +1,33 @@ + + + + + + + + Server Stats
    + RSS:

    + Heap total:

    + Heap used:

    + + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/server.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/server.js new file mode 100644 index 00000000..0bbce368 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/server.js @@ -0,0 +1,19 @@ +var WebSocketServer = require('../../').Server + , http = require('http') + , express = require('express') + , app = express.createServer(); + +app.use(express.static(__dirname + '/public')); +app.listen(8080); + +var wss = new WebSocketServer({server: app}); +wss.on('connection', function(ws) { + var id = setInterval(function() { + ws.send(JSON.stringify(process.memoryUsage()), function() { /* ignore errors */ }); + }, 100); + console.log('started client interval'); + ws.on('close', function() { + console.log('stopping client interval'); + clearInterval(id); + }) +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/ssl.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/ssl.js new file mode 100644 index 00000000..bf1bf530 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/ssl.js @@ -0,0 +1,59 @@ + +(function(){ + + "use strict"; + + var fs = require('fs'); + + // you'll probably load configuration from config + var cfg = { + ssl: true, + port: 8080, + ssl_key: '/path/to/you/ssl.key', + ssl_cert: '/path/to/you/ssl.crt' + }; + + var httpServ = ( cfg.ssl ) ? require('https') : require('http'); + + var WebSocketServer = require('../').Server; + + var app = null; + + // dummy request processing + var processRequest = function( req, res ) { + + res.writeHead(200); + res.end("All glory to WebSockets!\n"); + }; + + if ( cfg.ssl ) { + + app = httpServ.createServer({ + + // providing server with SSL key/cert + key: fs.readFileSync( cfg.ssl_key ), + cert: fs.readFileSync( cfg.ssl_cert ) + + }, processRequest ).listen( cfg.port ); + + } else { + + app = httpServ.createServer( processRequest ).listen( cfg.port ); + } + + // passing or reference to web server so WS would knew port and SSL capabilities + var wss = new WebSocketServer( { server: app } ); + + + wss.on( 'connection', function ( wsConnect ) { + + wsConnect.on( 'message', function ( message ) { + + console.log( message ); + + }); + + }); + + +}()); \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/index.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/index.js new file mode 100644 index 00000000..3423ff23 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/index.js @@ -0,0 +1,26 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports = require('./lib/WebSocket'); +module.exports.Server = require('./lib/WebSocketServer'); +module.exports.Sender = require('./lib/Sender'); +module.exports.Receiver = require('./lib/Receiver'); + +module.exports.createServer = function (options, connectionListener) { + var server = new module.exports.Server(options); + if (typeof connectionListener === 'function') { + server.on('connection', connectionListener); + } + return server; +}; + +module.exports.connect = module.exports.createConnection = function (address, openListener) { + var client = new module.exports(address); + if (typeof openListener === 'function') { + client.on('open', openListener); + } + return client; +}; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferPool.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferPool.js new file mode 100644 index 00000000..faf8637c --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferPool.js @@ -0,0 +1,59 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util'); + +function BufferPool(initialSize, growStrategy, shrinkStrategy) { + if (typeof initialSize === 'function') { + shrinkStrategy = growStrategy; + growStrategy = initialSize; + initialSize = 0; + } + else if (typeof initialSize === 'undefined') { + initialSize = 0; + } + this._growStrategy = (growStrategy || function(db, size) { + return db.used + size; + }).bind(null, this); + this._shrinkStrategy = (shrinkStrategy || function(db) { + return initialSize; + }).bind(null, this); + this._buffer = initialSize ? new Buffer(initialSize) : null; + this._offset = 0; + this._used = 0; + this._changeFactor = 0; + this.__defineGetter__('size', function(){ + return this._buffer == null ? 0 : this._buffer.length; + }); + this.__defineGetter__('used', function(){ + return this._used; + }); +} + +BufferPool.prototype.get = function(length) { + if (this._buffer == null || this._offset + length > this._buffer.length) { + var newBuf = new Buffer(this._growStrategy(length)); + this._buffer = newBuf; + this._offset = 0; + } + this._used += length; + var buf = this._buffer.slice(this._offset, this._offset + length); + this._offset += length; + return buf; +} + +BufferPool.prototype.reset = function(forceNewBuffer) { + var len = this._shrinkStrategy(); + if (len < this.size) this._changeFactor -= 1; + if (forceNewBuffer || this._changeFactor < -2) { + this._changeFactor = 0; + this._buffer = len ? new Buffer(len) : null; + } + this._offset = 0; + this._used = 0; +} + +module.exports = BufferPool; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferUtil.fallback.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferUtil.fallback.js new file mode 100644 index 00000000..508542c9 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferUtil.fallback.js @@ -0,0 +1,47 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports.BufferUtil = { + merge: function(mergedBuffer, buffers) { + var offset = 0; + for (var i = 0, l = buffers.length; i < l; ++i) { + var buf = buffers[i]; + buf.copy(mergedBuffer, offset); + offset += buf.length; + } + }, + mask: function(source, mask, output, offset, length) { + var maskNum = mask.readUInt32LE(0, true); + var i = 0; + for (; i < length - 3; i += 4) { + var num = maskNum ^ source.readUInt32LE(i, true); + if (num < 0) num = 4294967296 + num; + output.writeUInt32LE(num, offset + i, true); + } + switch (length % 4) { + case 3: output[offset + i + 2] = source[i + 2] ^ mask[2]; + case 2: output[offset + i + 1] = source[i + 1] ^ mask[1]; + case 1: output[offset + i] = source[i] ^ mask[0]; + case 0:; + } + }, + unmask: function(data, mask) { + var maskNum = mask.readUInt32LE(0, true); + var length = data.length; + var i = 0; + for (; i < length - 3; i += 4) { + var num = maskNum ^ data.readUInt32LE(i, true); + if (num < 0) num = 4294967296 + num; + data.writeUInt32LE(num, i, true); + } + switch (length % 4) { + case 3: data[i + 2] = data[i + 2] ^ mask[2]; + case 2: data[i + 1] = data[i + 1] ^ mask[1]; + case 1: data[i] = data[i] ^ mask[0]; + case 0:; + } + } +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferUtil.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferUtil.js new file mode 100644 index 00000000..15d35b98 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferUtil.js @@ -0,0 +1,16 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +try { + module.exports = require('../build/Release/bufferutil'); +} catch (e) { try { + module.exports = require('../build/default/bufferutil'); +} catch (e) { try { + module.exports = require('./BufferUtil.fallback'); +} catch (e) { + console.error('bufferutil.node seems to not have been built. Run npm install.'); + throw e; +}}} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/ErrorCodes.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/ErrorCodes.js new file mode 100644 index 00000000..55ebd529 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/ErrorCodes.js @@ -0,0 +1,24 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports = { + isValidErrorCode: function(code) { + return (code >= 1000 && code <= 1011 && code != 1004 && code != 1005 && code != 1006) || + (code >= 3000 && code <= 4999); + }, + 1000: 'normal', + 1001: 'going away', + 1002: 'protocol error', + 1003: 'unsupported data', + 1004: 'reserved', + 1005: 'reserved for extensions', + 1006: 'reserved for extensions', + 1007: 'inconsistent or invalid data', + 1008: 'policy violation', + 1009: 'message too big', + 1010: 'extension handshake missing', + 1011: 'an unexpected condition prevented the request from being fulfilled', +}; \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Receiver.hixie.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Receiver.hixie.js new file mode 100644 index 00000000..f54ad966 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Receiver.hixie.js @@ -0,0 +1,180 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util'); + +/** + * State constants + */ + +var EMPTY = 0 + , BODY = 1; +var BINARYLENGTH = 2 + , BINARYBODY = 3; + +/** + * Hixie Receiver implementation + */ + +function Receiver () { + this.state = EMPTY; + this.buffers = []; + this.messageEnd = -1; + this.spanLength = 0; + this.dead = false; + + this.onerror = function() {}; + this.ontext = function() {}; + this.onbinary = function() {}; + this.onclose = function() {}; + this.onping = function() {}; + this.onpong = function() {}; +} + +module.exports = Receiver; + +/** + * Add new data to the parser. + * + * @api public + */ + +Receiver.prototype.add = function(data) { + var self = this; + function doAdd() { + if (self.state === EMPTY) { + if (data.length == 2 && data[0] == 0xFF && data[1] == 0x00) { + self.reset(); + self.onclose(); + return; + } + if (data[0] === 0x80) { + self.messageEnd = 0; + self.state = BINARYLENGTH; + data = data.slice(1); + } else { + + if (data[0] !== 0x00) { + self.error('payload must start with 0x00 byte', true); + return; + } + data = data.slice(1); + self.state = BODY; + + } + } + if (self.state === BINARYLENGTH) { + var i = 0; + while ((i < data.length) && (data[i] & 0x80)) { + self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f); + ++i; + } + if (i < data.length) { + self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f); + self.state = BINARYBODY; + ++i; + } + if (i > 0) + data = data.slice(i); + } + if (self.state === BINARYBODY) { + var dataleft = self.messageEnd - self.spanLength; + if (data.length >= dataleft) { + // consume the whole buffer to finish the frame + self.buffers.push(data); + self.spanLength += dataleft; + self.messageEnd = dataleft; + return self.parse(); + } + // frame's not done even if we consume it all + self.buffers.push(data); + self.spanLength += data.length; + return; + } + self.buffers.push(data); + if ((self.messageEnd = bufferIndex(data, 0xFF)) != -1) { + self.spanLength += self.messageEnd; + return self.parse(); + } + else self.spanLength += data.length; + } + while(data) data = doAdd(); +} + +/** + * Releases all resources used by the receiver. + * + * @api public + */ + +Receiver.prototype.cleanup = function() { + this.dead = true; + this.state = EMPTY; + this.buffers = []; +} + +/** + * Process buffered data. + * + * @api public + */ + +Receiver.prototype.parse = function() { + var output = new Buffer(this.spanLength); + var outputIndex = 0; + for (var bi = 0, bl = this.buffers.length; bi < bl - 1; ++bi) { + var buffer = this.buffers[bi]; + buffer.copy(output, outputIndex); + outputIndex += buffer.length; + } + var lastBuffer = this.buffers[this.buffers.length - 1]; + if (this.messageEnd > 0) lastBuffer.copy(output, outputIndex, 0, this.messageEnd); + if (this.state !== BODY) --this.messageEnd; + var tail = null; + if (this.messageEnd < lastBuffer.length - 1) { + tail = lastBuffer.slice(this.messageEnd + 1); + } + this.reset(); + this.ontext(output.toString('utf8')); + return tail; +} + +/** + * Handles an error + * + * @api private + */ + +Receiver.prototype.error = function (reason, terminate) { + this.reset(); + this.onerror(reason, terminate); + return this; +} + +/** + * Reset parser state + * + * @api private + */ + +Receiver.prototype.reset = function (reason) { + if (this.dead) return; + this.state = EMPTY; + this.buffers = []; + this.messageEnd = -1; + this.spanLength = 0; +} + +/** + * Internal api + */ + +function bufferIndex(buffer, byte) { + for (var i = 0, l = buffer.length; i < l; ++i) { + if (buffer[i] === byte) return i; + } + return -1; +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Receiver.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Receiver.js new file mode 100644 index 00000000..2752726f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Receiver.js @@ -0,0 +1,591 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util') + , Validation = require('./Validation').Validation + , ErrorCodes = require('./ErrorCodes') + , BufferPool = require('./BufferPool') + , bufferUtil = require('./BufferUtil').BufferUtil; + +/** + * Node version 0.4 and 0.6 compatibility + */ + +var isNodeV4 = /^v0\.4/.test(process.version); + +/** + * HyBi Receiver implementation + */ + +function Receiver () { + // memory pool for fragmented messages + var fragmentedPoolPrevUsed = -1; + this.fragmentedBufferPool = new BufferPool(1024, function(db, length) { + return db.used + length; + }, function(db) { + return fragmentedPoolPrevUsed = fragmentedPoolPrevUsed >= 0 ? + (fragmentedPoolPrevUsed + db.used) / 2 : + db.used; + }); + + // memory pool for unfragmented messages + var unfragmentedPoolPrevUsed = -1; + this.unfragmentedBufferPool = new BufferPool(1024, function(db, length) { + return db.used + length; + }, function(db) { + return unfragmentedPoolPrevUsed = unfragmentedPoolPrevUsed >= 0 ? + (unfragmentedPoolPrevUsed + db.used) / 2 : + db.used; + }); + + this.state = { + activeFragmentedOperation: null, + lastFragment: false, + masked: false, + opcode: 0, + fragmentedOperation: false + }; + this.overflow = []; + this.headerBuffer = new Buffer(10); + this.expectOffset = 0; + this.expectBuffer = null; + this.expectHandler = null; + this.currentMessage = []; + this.expectHeader(2, this.processPacket); + this.dead = false; + + this.onerror = function() {}; + this.ontext = function() {}; + this.onbinary = function() {}; + this.onclose = function() {}; + this.onping = function() {}; + this.onpong = function() {}; +}; + +module.exports = Receiver; + +/** + * Add new data to the parser. + * + * @api public + */ + +Receiver.prototype.add = function(data) { + var dataLength = data.length; + if (dataLength == 0) return; + if (this.expectBuffer == null) { + this.overflow.push(data); + return; + } + var toRead = Math.min(dataLength, this.expectBuffer.length - this.expectOffset); + fastCopy(toRead, data, this.expectBuffer, this.expectOffset); + this.expectOffset += toRead; + if (toRead < dataLength) { + this.overflow.push(data.slice(toRead)); + } + while (this.expectBuffer && this.expectOffset == this.expectBuffer.length) { + var bufferForHandler = this.expectBuffer; + this.expectBuffer = null; + this.expectOffset = 0; + this.expectHandler.call(this, bufferForHandler); + } +} + +/** + * Releases all resources used by the receiver. + * + * @api public + */ + +Receiver.prototype.cleanup = function() { + this.dead = true; + this.overflow = null; + this.headerBuffer = null; + this.expectBuffer = null; + this.expectHandler = null; + this.unfragmentedBufferPool = null; + this.fragmentedBufferPool = null; + this.state = null; + this.currentMessage = null; + this.onerror = null; + this.ontext = null; + this.onbinary = null; + this.onclose = null; + this.onping = null; + this.onpong = null; +} + +/** + * Waits for a certain amount of header bytes to be available, then fires a callback. + * + * @api private + */ + +Receiver.prototype.expectHeader = function(length, handler) { + if (length == 0) { + handler(null); + return; + } + this.expectBuffer = this.headerBuffer.slice(this.expectOffset, this.expectOffset + length); + this.expectHandler = handler; + var toRead = length; + while (toRead > 0 && this.overflow.length > 0) { + var fromOverflow = this.overflow.pop(); + if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead)); + var read = Math.min(fromOverflow.length, toRead); + fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset); + this.expectOffset += read; + toRead -= read; + } +} + +/** + * Waits for a certain amount of data bytes to be available, then fires a callback. + * + * @api private + */ + +Receiver.prototype.expectData = function(length, handler) { + if (length == 0) { + handler(null); + return; + } + this.expectBuffer = this.allocateFromPool(length, this.state.fragmentedOperation); + this.expectHandler = handler; + var toRead = length; + while (toRead > 0 && this.overflow.length > 0) { + var fromOverflow = this.overflow.pop(); + if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead)); + var read = Math.min(fromOverflow.length, toRead); + fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset); + this.expectOffset += read; + toRead -= read; + } +} + +/** + * Allocates memory from the buffer pool. + * + * @api private + */ + +Receiver.prototype.allocateFromPool = !isNodeV4 + ? function(length, isFragmented) { return (isFragmented ? this.fragmentedBufferPool : this.unfragmentedBufferPool).get(length); } + : function(length) { return new Buffer(length); }; + +/** + * Start processing a new packet. + * + * @api private + */ + +Receiver.prototype.processPacket = function (data) { + if ((data[0] & 0x70) != 0) { + this.error('reserved fields must be empty', 1002); + return; + } + this.state.lastFragment = (data[0] & 0x80) == 0x80; + this.state.masked = (data[1] & 0x80) == 0x80; + var opcode = data[0] & 0xf; + if (opcode === 0) { + // continuation frame + this.state.fragmentedOperation = true; + this.state.opcode = this.state.activeFragmentedOperation; + if (!(this.state.opcode == 1 || this.state.opcode == 2)) { + this.error('continuation frame cannot follow current opcode', 1002); + return; + } + } + else { + if (opcode < 3 && this.state.activeFragmentedOperation != null) { + this.error('data frames after the initial data frame must have opcode 0', 1002); + return; + } + this.state.opcode = opcode; + if (this.state.lastFragment === false) { + this.state.fragmentedOperation = true; + this.state.activeFragmentedOperation = opcode; + } + else this.state.fragmentedOperation = false; + } + var handler = opcodes[this.state.opcode]; + if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode, 1002); + else { + handler.start.call(this, data); + } +} + +/** + * Endprocessing a packet. + * + * @api private + */ + +Receiver.prototype.endPacket = function() { + if (!this.state.fragmentedOperation) this.unfragmentedBufferPool.reset(true); + else if (this.state.lastFragment) this.fragmentedBufferPool.reset(false); + this.expectOffset = 0; + this.expectBuffer = null; + this.expectHandler = null; + if (this.state.lastFragment && this.state.opcode === this.state.activeFragmentedOperation) { + // end current fragmented operation + this.state.activeFragmentedOperation = null; + } + this.state.lastFragment = false; + this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0; + this.state.masked = false; + this.expectHeader(2, this.processPacket); +} + +/** + * Reset the parser state. + * + * @api private + */ + +Receiver.prototype.reset = function() { + if (this.dead) return; + this.state = { + activeFragmentedOperation: null, + lastFragment: false, + masked: false, + opcode: 0, + fragmentedOperation: false + }; + this.fragmentedBufferPool.reset(true); + this.unfragmentedBufferPool.reset(true); + this.expectOffset = 0; + this.expectBuffer = null; + this.expectHandler = null; + this.overflow = []; + this.currentMessage = []; +} + +/** + * Unmask received data. + * + * @api private + */ + +Receiver.prototype.unmask = function (mask, buf, binary) { + if (mask != null && buf != null) bufferUtil.unmask(buf, mask); + if (binary) return buf; + return buf != null ? buf.toString('utf8') : ''; +} + +/** + * Concatenates a list of buffers. + * + * @api private + */ + +Receiver.prototype.concatBuffers = function(buffers) { + var length = 0; + for (var i = 0, l = buffers.length; i < l; ++i) length += buffers[i].length; + var mergedBuffer = new Buffer(length); + bufferUtil.merge(mergedBuffer, buffers); + return mergedBuffer; +} + +/** + * Handles an error + * + * @api private + */ + +Receiver.prototype.error = function (reason, protocolErrorCode) { + this.reset(); + this.onerror(reason, protocolErrorCode); + return this; +} + +/** + * Buffer utilities + */ + +function readUInt16BE(start) { + return (this[start]<<8) + + this[start+1]; +} + +function readUInt32BE(start) { + return (this[start]<<24) + + (this[start+1]<<16) + + (this[start+2]<<8) + + this[start+3]; +} + +function fastCopy(length, srcBuffer, dstBuffer, dstOffset) { + switch (length) { + default: srcBuffer.copy(dstBuffer, dstOffset, 0, length); break; + case 16: dstBuffer[dstOffset+15] = srcBuffer[15]; + case 15: dstBuffer[dstOffset+14] = srcBuffer[14]; + case 14: dstBuffer[dstOffset+13] = srcBuffer[13]; + case 13: dstBuffer[dstOffset+12] = srcBuffer[12]; + case 12: dstBuffer[dstOffset+11] = srcBuffer[11]; + case 11: dstBuffer[dstOffset+10] = srcBuffer[10]; + case 10: dstBuffer[dstOffset+9] = srcBuffer[9]; + case 9: dstBuffer[dstOffset+8] = srcBuffer[8]; + case 8: dstBuffer[dstOffset+7] = srcBuffer[7]; + case 7: dstBuffer[dstOffset+6] = srcBuffer[6]; + case 6: dstBuffer[dstOffset+5] = srcBuffer[5]; + case 5: dstBuffer[dstOffset+4] = srcBuffer[4]; + case 4: dstBuffer[dstOffset+3] = srcBuffer[3]; + case 3: dstBuffer[dstOffset+2] = srcBuffer[2]; + case 2: dstBuffer[dstOffset+1] = srcBuffer[1]; + case 1: dstBuffer[dstOffset] = srcBuffer[0]; + } +} + +/** + * Opcode handlers + */ + +var opcodes = { + // text + '1': { + start: function(data) { + var self = this; + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['1'].getData.call(self, firstLength); + } + else if (firstLength == 126) { + self.expectHeader(2, function(data) { + opcodes['1'].getData.call(self, readUInt16BE.call(data, 0)); + }); + } + else if (firstLength == 127) { + self.expectHeader(8, function(data) { + if (readUInt32BE.call(data, 0) != 0) { + self.error('packets with length spanning more than 32 bit is currently not supported', 1008); + return; + } + opcodes['1'].getData.call(self, readUInt32BE.call(data, 4)); + }); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['1'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['1'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var packet = this.unmask(mask, data, true); + if (packet != null) this.currentMessage.push(packet); + if (this.state.lastFragment) { + var messageBuffer = this.concatBuffers(this.currentMessage); + if (!Validation.isValidUTF8(messageBuffer)) { + this.error('invalid utf8 sequence', 1007); + return; + } + this.ontext(messageBuffer.toString('utf8'), {masked: this.state.masked, buffer: messageBuffer}); + this.currentMessage = []; + } + this.endPacket(); + } + }, + // binary + '2': { + start: function(data) { + var self = this; + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['2'].getData.call(self, firstLength); + } + else if (firstLength == 126) { + self.expectHeader(2, function(data) { + opcodes['2'].getData.call(self, readUInt16BE.call(data, 0)); + }); + } + else if (firstLength == 127) { + self.expectHeader(8, function(data) { + if (readUInt32BE.call(data, 0) != 0) { + self.error('packets with length spanning more than 32 bit is currently not supported', 1008); + return; + } + opcodes['2'].getData.call(self, readUInt32BE.call(data, 4, true)); + }); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['2'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['2'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var packet = this.unmask(mask, data, true); + if (packet != null) this.currentMessage.push(packet); + if (this.state.lastFragment) { + var messageBuffer = this.concatBuffers(this.currentMessage); + this.onbinary(messageBuffer, {masked: this.state.masked, buffer: messageBuffer}); + this.currentMessage = []; + } + this.endPacket(); + } + }, + // close + '8': { + start: function(data) { + var self = this; + if (self.state.lastFragment == false) { + self.error('fragmented close is not supported', 1002); + return; + } + + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['8'].getData.call(self, firstLength); + } + else { + self.error('control frames cannot have more than 125 bytes of data', 1002); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['8'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['8'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var self = this; + data = self.unmask(mask, data, true); + if (data && data.length == 1) { + self.error('close packets with data must be at least two bytes long', 1002); + return; + } + var code = data && data.length > 1 ? readUInt16BE.call(data, 0) : 1000; + if (!ErrorCodes.isValidErrorCode(code)) { + self.error('invalid error code', 1002); + return; + } + var message = ''; + if (data && data.length > 2) { + var messageBuffer = data.slice(2); + if (!Validation.isValidUTF8(messageBuffer)) { + self.error('invalid utf8 sequence', 1007); + return; + } + message = messageBuffer.toString('utf8'); + } + this.onclose(code, message, {masked: self.state.masked}); + this.reset(); + }, + }, + // ping + '9': { + start: function(data) { + var self = this; + if (self.state.lastFragment == false) { + self.error('fragmented ping is not supported', 1002); + return; + } + + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['9'].getData.call(self, firstLength); + } + else { + self.error('control frames cannot have more than 125 bytes of data', 1002); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['9'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['9'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + this.onping(this.unmask(mask, data, true), {masked: this.state.masked, binary: true}); + this.endPacket(); + } + }, + // pong + '10': { + start: function(data) { + var self = this; + if (self.state.lastFragment == false) { + self.error('fragmented pong is not supported', 1002); + return; + } + + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['10'].getData.call(self, firstLength); + } + else { + self.error('control frames cannot have more than 125 bytes of data', 1002); + } + }, + getData: function(length) { + var self = this; + if (this.state.masked) { + this.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['10'].finish.call(self, mask, data); + }); + }); + } + else { + this.expectData(length, function(data) { + opcodes['10'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + this.onpong(this.unmask(mask, data, true), {masked: this.state.masked, binary: true}); + this.endPacket(); + } + } +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Sender.hixie.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Sender.hixie.js new file mode 100644 index 00000000..1754afb6 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Sender.hixie.js @@ -0,0 +1,123 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var events = require('events') + , util = require('util') + , EventEmitter = events.EventEmitter; + +/** + * Hixie Sender implementation + */ + +function Sender(socket) { + this.socket = socket; + this.continuationFrame = false; + this.isClosed = false; +} + +module.exports = Sender; + +/** + * Inherits from EventEmitter. + */ + +util.inherits(Sender, events.EventEmitter); + +/** + * Frames and writes data. + * + * @api public + */ + +Sender.prototype.send = function(data, options, cb) { + if (this.isClosed) return; +/* + if (options && options.binary) { + this.error('hixie websockets do not support binary'); + return; + } +*/ + var isString = typeof data == 'string' + , length = isString ? Buffer.byteLength(data) : data.length + , lengthbytes = (length > 127) ? 2 : 1 // assume less than 2**14 bytes + , writeStartMarker = this.continuationFrame == false + , writeEndMarker = !options || !(typeof options.fin != 'undefined' && !options.fin) + , buffer = new Buffer((writeStartMarker ? ((options && options.binary) ? (1 + lengthbytes) : 1) : 0) + length + ((writeEndMarker && !(options && options.binary)) ? 1 : 0)) + , offset = writeStartMarker ? 1 : 0; + + if (writeStartMarker) { + if (options && options.binary) { + buffer.write('\x80', 'binary'); + // assume length less than 2**14 bytes + if (lengthbytes > 1) + buffer.write(String.fromCharCode(128+length/128), offset++, 'binary'); + buffer.write(String.fromCharCode(length&0x7f), offset++, 'binary'); + } else + buffer.write('\x00', 'binary'); + } + + if (isString) buffer.write(data, offset, 'utf8'); + else data.copy(buffer, offset, 0); + + if (writeEndMarker) { + if (options && options.binary) { + // sending binary, not writing end marker + } else + buffer.write('\xff', offset + length, 'binary'); + this.continuationFrame = false; + } + else this.continuationFrame = true; + + try { + this.socket.write(buffer, 'binary', cb); + } catch (e) { + this.error(e.toString()); + } +} + +/** + * Sends a close instruction to the remote party. + * + * @api public + */ + +Sender.prototype.close = function(code, data, mask, cb) { + if (this.isClosed) return; + this.isClosed = true; + try { + if (this.continuationFrame) this.socket.write(new Buffer([0xff], 'binary')); + this.socket.write(new Buffer([0xff, 0x00]), 'binary', cb); + } catch (e) { + this.error(e.toString()); + } +} + +/** + * Sends a ping message to the remote party. Not available for hixie. + * + * @api public + */ + +Sender.prototype.ping = function(data, options) {} + +/** + * Sends a pong message to the remote party. Not available for hixie. + * + * @api public + */ + +Sender.prototype.pong = function(data, options) {} + +/** + * Handles an error + * + * @api private + */ + +Sender.prototype.error = function (reason) { + this.emit('error', reason); + return this; +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Sender.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Sender.js new file mode 100644 index 00000000..fc3b4378 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Sender.js @@ -0,0 +1,227 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var events = require('events') + , util = require('util') + , EventEmitter = events.EventEmitter + , ErrorCodes = require('./ErrorCodes') + , bufferUtil = require('./BufferUtil').BufferUtil; + +/** + * HyBi Sender implementation + */ + +function Sender(socket) { + this._socket = socket; + this.firstFragment = true; +} + +/** + * Inherits from EventEmitter. + */ + +util.inherits(Sender, events.EventEmitter); + +/** + * Sends a close instruction to the remote party. + * + * @api public + */ + +Sender.prototype.close = function(code, data, mask) { + if (typeof code !== 'undefined') { + if (typeof code !== 'number' || + !ErrorCodes.isValidErrorCode(code)) throw new Error('first argument must be a valid error code number'); + } + code = code || 1000; + var dataBuffer = new Buffer(2 + (data ? Buffer.byteLength(data) : 0)); + writeUInt16BE.call(dataBuffer, code, 0); + if (dataBuffer.length > 2) dataBuffer.write(data, 2); + this.frameAndSend(0x8, dataBuffer, true, mask); +} + +/** + * Sends a ping message to the remote party. + * + * @api public + */ + +Sender.prototype.ping = function(data, options) { + var mask = options && options.mask; + this.frameAndSend(0x9, data || '', true, mask); +} + +/** + * Sends a pong message to the remote party. + * + * @api public + */ + +Sender.prototype.pong = function(data, options) { + var mask = options && options.mask; + this.frameAndSend(0xa, data || '', true, mask); +} + +/** + * Sends text or binary data to the remote party. + * + * @api public + */ + +Sender.prototype.send = function(data, options, cb) { + var finalFragment = options && options.fin === false ? false : true; + var mask = options && options.mask; + var opcode = options && options.binary ? 2 : 1; + if (this.firstFragment === false) opcode = 0; + else this.firstFragment = false; + if (finalFragment) this.firstFragment = true + this.frameAndSend(opcode, data, finalFragment, mask, cb); +} + +/** + * Frames and sends a piece of data according to the HyBi WebSocket protocol. + * + * @api private + */ + +Sender.prototype.frameAndSend = function(opcode, data, finalFragment, maskData, cb) { + var canModifyData = false; + + if (!data) { + try { + this._socket.write(new Buffer([opcode | (finalFragment ? 0x80 : 0), 0 | (maskData ? 0x80 : 0)].concat(maskData ? [0, 0, 0, 0] : [])), 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + return; + } + + if (!Buffer.isBuffer(data)) { + canModifyData = true; + if (data && (typeof data.byteLength !== 'undefined' || typeof data.buffer !== 'undefined')) { + data = getArrayBuffer(data); + } else { + data = new Buffer(data); + } + } + + var dataLength = data.length + , dataOffset = maskData ? 6 : 2 + , secondByte = dataLength; + + if (dataLength >= 65536) { + dataOffset += 8; + secondByte = 127; + } + else if (dataLength > 125) { + dataOffset += 2; + secondByte = 126; + } + + var mergeBuffers = dataLength < 32768 || (maskData && !canModifyData); + var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset; + var outputBuffer = new Buffer(totalLength); + outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode; + + switch (secondByte) { + case 126: + writeUInt16BE.call(outputBuffer, dataLength, 2); + break; + case 127: + writeUInt32BE.call(outputBuffer, 0, 2); + writeUInt32BE.call(outputBuffer, dataLength, 6); + } + + if (maskData) { + outputBuffer[1] = secondByte | 0x80; + var mask = this._randomMask || (this._randomMask = getRandomMask()); + outputBuffer[dataOffset - 4] = mask[0]; + outputBuffer[dataOffset - 3] = mask[1]; + outputBuffer[dataOffset - 2] = mask[2]; + outputBuffer[dataOffset - 1] = mask[3]; + if (mergeBuffers) { + bufferUtil.mask(data, mask, outputBuffer, dataOffset, dataLength); + try { + this._socket.write(outputBuffer, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + else { + bufferUtil.mask(data, mask, data, 0, dataLength); + try { + this._socket.write(outputBuffer, 'binary'); + this._socket.write(data, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + } + else { + outputBuffer[1] = secondByte; + if (mergeBuffers) { + data.copy(outputBuffer, dataOffset); + try { + this._socket.write(outputBuffer, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + else { + try { + this._socket.write(outputBuffer, 'binary'); + this._socket.write(data, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + } +} + +module.exports = Sender; + +function writeUInt16BE(value, offset) { + this[offset] = (value & 0xff00)>>8; + this[offset+1] = value & 0xff; +} + +function writeUInt32BE(value, offset) { + this[offset] = (value & 0xff000000)>>24; + this[offset+1] = (value & 0xff0000)>>16; + this[offset+2] = (value & 0xff00)>>8; + this[offset+3] = value & 0xff; +} + +function getArrayBuffer(data) { + // data is either an ArrayBuffer or ArrayBufferView. + var array = new Uint8Array(data.buffer || data) + , l = data.byteLength || data.length + , o = data.byteOffset || 0 + , buffer = new Buffer(l); + for (var i = 0; i < l; ++i) { + buffer[i] = array[o+i]; + } + return buffer; +} + +function getRandomMask() { + return new Buffer([ + ~~(Math.random() * 255), + ~~(Math.random() * 255), + ~~(Math.random() * 255), + ~~(Math.random() * 255) + ]); +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Validation.fallback.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Validation.fallback.js new file mode 100644 index 00000000..2c7c4fd4 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Validation.fallback.js @@ -0,0 +1,12 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports.Validation = { + isValidUTF8: function(buffer) { + return true; + } +}; + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Validation.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Validation.js new file mode 100644 index 00000000..0f3109a0 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Validation.js @@ -0,0 +1,16 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +try { + module.exports = require('../build/Release/validation'); +} catch (e) { try { + module.exports = require('../build/default/validation'); +} catch (e) { try { + module.exports = require('./Validation.fallback'); +} catch (e) { + console.error('validation.node seems to not have been built. Run npm install.'); + throw e; +}}} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/WebSocket.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/WebSocket.js new file mode 100644 index 00000000..cce3cb41 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/WebSocket.js @@ -0,0 +1,818 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util') + , events = require('events') + , http = require('http') + , https = require('https') + , crypto = require('crypto') + , url = require('url') + , fs = require('fs') + , Options = require('options') + , Sender = require('./Sender') + , Receiver = require('./Receiver') + , SenderHixie = require('./Sender.hixie') + , ReceiverHixie = require('./Receiver.hixie'); + +/** + * Constants + */ + +// Default protocol version + +var protocolVersion = 13; + +// Close timeout + +var closeTimeout = 30000; // Allow 5 seconds to terminate the connection cleanly + +/** + * Node version 0.4 and 0.6 compatibility + */ + +var isNodeV4 = /^v0\.4/.test(process.version); + +/** + * WebSocket implementation + */ + +function WebSocket(address, protocols, options) { + + if (protocols && !Array.isArray(protocols) && 'object' == typeof protocols) { + // accept the "options" Object as the 2nd argument + options = protocols; + protocols = null; + } + if ('string' == typeof protocols) { + protocols = [ protocols ]; + } + if (!Array.isArray(protocols)) { + protocols = []; + } + // TODO: actually handle the `Sub-Protocols` part of the WebSocket client + + this._socket = null; + this.bytesReceived = 0; + this.readyState = null; + this.supports = {}; + + if (Array.isArray(address)) { + initAsServerClient.apply(this, address.concat(options)); + } else { + initAsClient.apply(this, [address, protocols, options]); + } +} + +/** + * Inherits from EventEmitter. + */ + +util.inherits(WebSocket, events.EventEmitter); + +/** + * Ready States + */ + +["CONNECTING", "OPEN", "CLOSING", "CLOSED"].forEach(function (state, index) { + WebSocket.prototype[state] = WebSocket[state] = index; +}); + +/** + * Gracefully closes the connection, after sending a description message to the server + * + * @param {Object} data to be sent to the server + * @api public + */ + +WebSocket.prototype.close = function(code, data) { + if (this.readyState == WebSocket.CLOSING || this.readyState == WebSocket.CLOSED) return; + if (this.readyState == WebSocket.CONNECTING) { + this.readyState = WebSocket.CLOSED; + return; + } + try { + this.readyState = WebSocket.CLOSING; + this._closeCode = code; + this._closeMessage = data; + var mask = !this._isServer; + this._sender.close(code, data, mask); + } + catch (e) { + this.emit('error', e); + } + finally { + this.terminate(); + } +} + +/** + * Pause the client stream + * + * @api public + */ + +WebSocket.prototype.pause = function() { + if (this.readyState != WebSocket.OPEN) throw new Error('not opened'); + return this._socket.pause(); +} + +/** + * Sends a ping + * + * @param {Object} data to be sent to the server + * @param {Object} Members - mask: boolean, binary: boolean + * @param {boolean} dontFailWhenClosed indicates whether or not to throw if the connection isnt open + * @api public + */ + +WebSocket.prototype.ping = function(data, options, dontFailWhenClosed) { + if (this.readyState != WebSocket.OPEN) { + if (dontFailWhenClosed === true) return; + throw new Error('not opened'); + } + options = options || {}; + if (typeof options.mask == 'undefined') options.mask = !this._isServer; + this._sender.ping(data, options); +} + +/** + * Sends a pong + * + * @param {Object} data to be sent to the server + * @param {Object} Members - mask: boolean, binary: boolean + * @param {boolean} dontFailWhenClosed indicates whether or not to throw if the connection isnt open + * @api public + */ + +WebSocket.prototype.pong = function(data, options, dontFailWhenClosed) { + if (this.readyState != WebSocket.OPEN) { + if (dontFailWhenClosed === true) return; + throw new Error('not opened'); + } + options = options || {}; + if (typeof options.mask == 'undefined') options.mask = !this._isServer; + this._sender.pong(data, options); +} + +/** + * Resume the client stream + * + * @api public + */ + +WebSocket.prototype.resume = function() { + if (this.readyState != WebSocket.OPEN) throw new Error('not opened'); + return this._socket.resume(); +} + +/** + * Sends a piece of data + * + * @param {Object} data to be sent to the server + * @param {Object} Members - mask: boolean, binary: boolean + * @param {function} Optional callback which is executed after the send completes + * @api public + */ + +WebSocket.prototype.send = function(data, options, cb) { + if (typeof options == 'function') { + cb = options; + options = {}; + } + if (this.readyState != WebSocket.OPEN) { + if (typeof cb == 'function') cb(new Error('not opened')); + else throw new Error('not opened'); + return; + } + if (!data) data = ''; + if (this._queue) { + var self = this; + this._queue.push(function() { self.send(data, options, cb); }); + return; + } + options = options || {}; + options.fin = true; + if (typeof options.binary == 'undefined') { + options.binary = (data instanceof ArrayBuffer || data instanceof Buffer || + data instanceof Uint8Array || + data instanceof Uint16Array || + data instanceof Uint32Array || + data instanceof Int8Array || + data instanceof Int16Array || + data instanceof Int32Array || + data instanceof Float32Array || + data instanceof Float64Array); + } + if (typeof options.mask == 'undefined') options.mask = !this._isServer; + if (data instanceof fs.ReadStream) { + startQueue(this); + var self = this; + sendStream(this, data, options, function(error) { + process.nextTick(function() { executeQueueSends(self); }); + if (typeof cb == 'function') cb(error); + }); + } + else this._sender.send(data, options, cb); +} + +/** + * Streams data through calls to a user supplied function + * + * @param {Object} Members - mask: boolean, binary: boolean + * @param {function} 'function (error, send)' which is executed on successive ticks of which send is 'function (data, final)'. + * @api public + */ + +WebSocket.prototype.stream = function(options, cb) { + if (typeof options == 'function') { + cb = options; + options = {}; + } + var self = this; + if (typeof cb != 'function') throw new Error('callback must be provided'); + if (this.readyState != WebSocket.OPEN) { + if (typeof cb == 'function') cb(new Error('not opened')); + else throw new Error('not opened'); + return; + } + if (this._queue) { + this._queue.push(function() { self.stream(options, cb); }); + return; + } + options = options || {}; + if (typeof options.mask == 'undefined') options.mask = !this._isServer; + startQueue(this); + var send = function(data, final) { + try { + if (self.readyState != WebSocket.OPEN) throw new Error('not opened'); + options.fin = final === true; + self._sender.send(data, options); + if (!final) process.nextTick(cb.bind(null, null, send)); + else executeQueueSends(self); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else { + delete self._queue; + self.emit('error', e); + } + } + } + process.nextTick(cb.bind(null, null, send)); +} + +/** + * Immediately shuts down the connection + * + * @api public + */ + +WebSocket.prototype.terminate = function() { + if (this.readyState == WebSocket.CLOSED) return; + if (this._socket) { + try { + // End the connection + this._socket.end(); + } + catch (e) { + // Socket error during end() call, so just destroy it right now + cleanupWebsocketResources.call(this, true); + return; + } + + // Add a timeout to ensure that the connection is completely + // cleaned up within 30 seconds, even if the clean close procedure + // fails for whatever reason + this._closeTimer = setTimeout(cleanupWebsocketResources.bind(this, true), closeTimeout); + } + else if (this.readyState == WebSocket.CONNECTING) { + cleanupWebsocketResources.call(this, true); + } +}; + +/** + * Expose bufferedAmount + * + * @api public + */ + +Object.defineProperty(WebSocket.prototype, 'bufferedAmount', { + get: function get() { + var amount = 0; + if (this._socket) { + amount = this._socket.bufferSize || 0; + } + return amount; + } +}); + +/** + * Emulates the W3C Browser based WebSocket interface using function members. + * + * @see http://dev.w3.org/html5/websockets/#the-websocket-interface + * @api public + */ + +['open', 'error', 'close', 'message'].forEach(function(method) { + Object.defineProperty(WebSocket.prototype, 'on' + method, { + /** + * Returns the current listener + * + * @returns {Mixed} the set function or undefined + * @api public + */ + + get: function get() { + var listener = this.listeners(method)[0]; + return listener ? (listener._listener ? listener._listener : listener) : undefined; + }, + + /** + * Start listening for events + * + * @param {Function} listener the listener + * @returns {Mixed} the set function or undefined + * @api public + */ + + set: function set(listener) { + this.removeAllListeners(method); + this.addEventListener(method, listener); + } + }); +}); + +/** + * Emulates the W3C Browser based WebSocket interface using addEventListener. + * + * @see https://developer.mozilla.org/en/DOM/element.addEventListener + * @see http://dev.w3.org/html5/websockets/#the-websocket-interface + * @api public + */ +WebSocket.prototype.addEventListener = function(method, listener) { + var target = this; + if (typeof listener === 'function') { + if (method === 'message') { + function onMessage (data, flags) { + listener.call(this, new MessageEvent(data, flags.binary ? 'Binary' : 'Text', target)); + } + // store a reference so we can return the original function from the addEventListener hook + onMessage._listener = listener; + this.on(method, onMessage); + } else if (method === 'close') { + function onClose (code, message) { + listener.call(this, new CloseEvent(code, message, target)); + } + // store a reference so we can return the original function from the addEventListener hook + onClose._listener = listener; + this.on(method, onClose); + } else if (method === 'error') { + function onError (event) { + event.target = target; + listener.call(this, event); + } + // store a reference so we can return the original function from the addEventListener hook + onError._listener = listener; + this.on(method, onError); + } else if (method === 'open') { + function onOpen () { + listener.call(this, new OpenEvent(target)); + } + // store a reference so we can return the original function from the addEventListener hook + onOpen._listener = listener; + this.on(method, onOpen); + } else { + this.on(method, listener); + } + } +} + +module.exports = WebSocket; + +/** + * W3C MessageEvent + * + * @see http://www.w3.org/TR/html5/comms.html + * @api private + */ + +function MessageEvent(dataArg, typeArg, target) { + this.data = dataArg; + this.type = typeArg; + this.target = target; +} + +/** + * W3C CloseEvent + * + * @see http://www.w3.org/TR/html5/comms.html + * @api private + */ + +function CloseEvent(code, reason, target) { + this.wasClean = (typeof code == 'undefined' || code == 1000); + this.code = code; + this.reason = reason; + this.target = target; +} + +/** + * W3C OpenEvent + * + * @see http://www.w3.org/TR/html5/comms.html + * @api private + */ + +function OpenEvent(target) { + this.target = target; +} + +/** + * Entirely private apis, + * which may or may not be bound to a sepcific WebSocket instance. + */ + +function initAsServerClient(req, socket, upgradeHead, options) { + options = new Options({ + protocolVersion: protocolVersion, + protocol: null + }).merge(options); + + // expose state properties + this.protocol = options.value.protocol; + this.protocolVersion = options.value.protocolVersion; + this.supports.binary = (this.protocolVersion != 'hixie-76'); + this.upgradeReq = req; + this.readyState = WebSocket.CONNECTING; + this._isServer = true; + + // establish connection + if (options.value.protocolVersion == 'hixie-76') establishConnection.call(this, ReceiverHixie, SenderHixie, socket, upgradeHead); + else establishConnection.call(this, Receiver, Sender, socket, upgradeHead); +} + +function initAsClient(address, protocols, options) { + options = new Options({ + origin: null, + protocolVersion: protocolVersion, + host: null, + headers: null, + protocol: null, + agent: null, + + // ssl-related options + pfx: null, + key: null, + passphrase: null, + cert: null, + ca: null, + ciphers: null, + rejectUnauthorized: null + }).merge(options); + if (options.value.protocolVersion != 8 && options.value.protocolVersion != 13) { + throw new Error('unsupported protocol version'); + } + + // verify url and establish http class + var serverUrl = url.parse(address); + var isUnixSocket = serverUrl.protocol === 'ws+unix:'; + if (!serverUrl.host && !isUnixSocket) throw new Error('invalid url'); + var isSecure = serverUrl.protocol === 'wss:' || serverUrl.protocol === 'https:'; + var httpObj = isSecure ? https : http; + var port = serverUrl.port || (isSecure ? 443 : 80); + var auth = serverUrl.auth; + + // expose state properties + this._isServer = false; + this.url = address; + this.protocolVersion = options.value.protocolVersion; + this.supports.binary = (this.protocolVersion != 'hixie-76'); + + // begin handshake + var key = new Buffer(options.value.protocolVersion + '-' + Date.now()).toString('base64'); + var shasum = crypto.createHash('sha1'); + shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'); + var expectedServerKey = shasum.digest('base64'); + + var agent = options.value.agent; + // node<=v0.4.x compatibility + if (!agent && isNodeV4) { + isNodeV4 = true; + agent = new httpObj.Agent({ + host: serverUrl.hostname, + port: port + }); + } + + var headerHost = serverUrl.hostname; + // Append port number to Host and Origin header, only if specified in the url and non-default + if(serverUrl.port) { + if((isSecure && (port != 443)) || (!isSecure && (port != 80))){ + headerHost = headerHost + ':' + port; + } + } + + var requestOptions = { + port: port, + host: serverUrl.hostname, + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Host': headerHost, + 'Origin': headerHost, + 'Sec-WebSocket-Version': options.value.protocolVersion, + 'Sec-WebSocket-Key': key + } + }; + + // If we have basic auth. + if (auth) { + requestOptions.headers['Authorization'] = 'Basic ' + new Buffer(auth).toString('base64'); + } + + if (options.value.protocol) { + requestOptions.headers['Sec-WebSocket-Protocol'] = options.value.protocol; + } + + if (options.value.host) { + requestOptions.headers['Host'] = options.value.host; + } + + if (options.value.headers) { + for (var header in options.value.headers) { + if (options.value.headers.hasOwnProperty(header)) { + requestOptions.headers[header] = options.value.headers[header]; + } + } + } + + if (options.isDefinedAndNonNull('pfx') + || options.isDefinedAndNonNull('key') + || options.isDefinedAndNonNull('passphrase') + || options.isDefinedAndNonNull('cert') + || options.isDefinedAndNonNull('ca') + || options.isDefinedAndNonNull('ciphers') + || options.isDefinedAndNonNull('rejectUnauthorized')) { + + if (isNodeV4) { + throw new Error('Client side certificates are not supported on Node 0.4.x'); + } + + if (options.isDefinedAndNonNull('pfx')) requestOptions.pfx = options.value.pfx; + if (options.isDefinedAndNonNull('key')) requestOptions.key = options.value.key; + if (options.isDefinedAndNonNull('passphrase')) requestOptions.passphrase = options.value.passphrase; + if (options.isDefinedAndNonNull('cert')) requestOptions.cert = options.value.cert; + if (options.isDefinedAndNonNull('ca')) requestOptions.ca = options.value.ca; + if (options.isDefinedAndNonNull('ciphers')) requestOptions.ciphers = options.value.ciphers; + if (options.isDefinedAndNonNull('rejectUnauthorized')) requestOptions.rejectUnauthorized = options.value.rejectUnauthorized; + + if (!agent) { + // global agent ignores client side certificates + agent = new httpObj.Agent(requestOptions); + } + } + + if (isNodeV4) { + requestOptions.path = (serverUrl.pathname || '/') + (serverUrl.search || ''); + } + else requestOptions.path = serverUrl.path || '/'; + + if (agent) { + requestOptions.agent = agent; + } + + if (isUnixSocket) { + requestOptions.socketPath = serverUrl.pathname; + } + if (options.value.origin) { + if (options.value.protocolVersion < 13) requestOptions.headers['Sec-WebSocket-Origin'] = options.value.origin; + else requestOptions.headers['Origin'] = options.value.origin; + } + + var self = this; + var req = httpObj.request(requestOptions); + + (isNodeV4 ? agent : req).on('error', function(error) { + self.emit('error', error); + cleanupWebsocketResources.call(this, error); + }); + (isNodeV4 ? agent : req).once('response', function(res) { + var error = new Error('unexpected server response (' + res.statusCode + ')'); + self.emit('error', error); + cleanupWebsocketResources.call(this, error); + }); + (isNodeV4 ? agent : req).once('upgrade', function(res, socket, upgradeHead) { + if (self.readyState == WebSocket.CLOSED) { + // client closed before server accepted connection + self.emit('close'); + removeAllListeners(self); + socket.end(); + return; + } + var serverKey = res.headers['sec-websocket-accept']; + if (typeof serverKey == 'undefined' || serverKey !== expectedServerKey) { + self.emit('error', 'invalid server key'); + removeAllListeners(self); + socket.end(); + return; + } + + var serverProt = res.headers['sec-websocket-protocol']; + var protList = (options.value.protocol || "").split(/, */); + var protError = null; + if (!options.value.protocol && serverProt) { + protError = 'server sent a subprotocol even though none requested'; + } else if (options.value.protocol && !serverProt) { + protError = 'server sent no subprotocol even though requested'; + } else if (serverProt && protList.indexOf(serverProt) === -1) { + protError = 'server responded with an invalid protocol'; + } + if (protError) { + self.emit('error', protError); + removeAllListeners(self); + socket.end(); + return; + } else if (serverProt) { + self.protocol = serverProt; + } + + establishConnection.call(self, Receiver, Sender, socket, upgradeHead); + + // perform cleanup on http resources + removeAllListeners(isNodeV4 ? agent : req); + req = null; + agent = null; + }); + + req.end(); + this.readyState = WebSocket.CONNECTING; +} + +function establishConnection(ReceiverClass, SenderClass, socket, upgradeHead) { + this._socket = socket; + socket.setTimeout(0); + socket.setNoDelay(true); + var self = this; + this._receiver = new ReceiverClass(); + + // socket cleanup handlers + socket.on('end', cleanupWebsocketResources.bind(this)); + socket.on('close', cleanupWebsocketResources.bind(this)); + socket.on('error', cleanupWebsocketResources.bind(this)); + + // ensure that the upgradeHead is added to the receiver + function firstHandler(data) { + if (self.readyState != WebSocket.OPEN) return; + if (upgradeHead && upgradeHead.length > 0) { + self.bytesReceived += upgradeHead.length; + var head = upgradeHead; + upgradeHead = null; + self._receiver.add(head); + } + dataHandler = realHandler; + if (data) { + self.bytesReceived += data.length; + self._receiver.add(data); + } + } + // subsequent packets are pushed straight to the receiver + function realHandler(data) { + if (data) self.bytesReceived += data.length; + self._receiver.add(data); + } + var dataHandler = firstHandler; + // if data was passed along with the http upgrade, + // this will schedule a push of that on to the receiver. + // this has to be done on next tick, since the caller + // hasn't had a chance to set event handlers on this client + // object yet. + process.nextTick(firstHandler); + + // receiver event handlers + self._receiver.ontext = function (data, flags) { + flags = flags || {}; + self.emit('message', data, flags); + }; + self._receiver.onbinary = function (data, flags) { + flags = flags || {}; + flags.binary = true; + self.emit('message', data, flags); + }; + self._receiver.onping = function(data, flags) { + flags = flags || {}; + self.pong(data, {mask: !self._isServer, binary: flags.binary === true}, true); + self.emit('ping', data, flags); + }; + self._receiver.onpong = function(data, flags) { + self.emit('pong', data, flags); + }; + self._receiver.onclose = function(code, data, flags) { + flags = flags || {}; + self.close(code, data); + }; + self._receiver.onerror = function(reason, errorCode) { + // close the connection when the receiver reports a HyBi error code + self.close(typeof errorCode != 'undefined' ? errorCode : 1002, ''); + self.emit('error', reason, errorCode); + }; + + // finalize the client + this._sender = new SenderClass(socket); + this._sender.on('error', function(error) { + self.close(1002, ''); + self.emit('error', error); + }); + this.readyState = WebSocket.OPEN; + this.emit('open'); + + socket.on('data', dataHandler); +} + +function startQueue(instance) { + instance._queue = instance._queue || []; +} + +function executeQueueSends(instance) { + var queue = instance._queue; + if (typeof queue == 'undefined') return; + delete instance._queue; + for (var i = 0, l = queue.length; i < l; ++i) { + queue[i](); + } +} + +function sendStream(instance, stream, options, cb) { + stream.on('data', function(data) { + if (instance.readyState != WebSocket.OPEN) { + if (typeof cb == 'function') cb(new Error('not opened')); + else { + delete instance._queue; + instance.emit('error', new Error('not opened')); + } + return; + } + options.fin = false; + instance._sender.send(data, options); + }); + stream.on('end', function() { + if (instance.readyState != WebSocket.OPEN) { + if (typeof cb == 'function') cb(new Error('not opened')); + else { + delete instance._queue; + instance.emit('error', new Error('not opened')); + } + return; + } + options.fin = true; + instance._sender.send(null, options); + if (typeof cb == 'function') cb(null); + }); +} + +function cleanupWebsocketResources(error) { + if (this.readyState == WebSocket.CLOSED) return; + var emitClose = this.readyState != WebSocket.CONNECTING; + this.readyState = WebSocket.CLOSED; + + clearTimeout(this._closeTimer); + this._closeTimer = null; + if (emitClose) this.emit('close', this._closeCode || 1000, this._closeMessage || ''); + + if (this._socket) { + removeAllListeners(this._socket); + // catch all socket error after removing all standard handlers + var socket = this._socket; + this._socket.on('error', function() { + try { socket.destroy(); } catch (e) {} + }); + try { + if (!error) this._socket.end(); + else this._socket.destroy(); + } + catch (e) { /* Ignore termination errors */ } + this._socket = null; + } + if (this._sender) { + removeAllListeners(this._sender); + this._sender = null; + } + if (this._receiver) { + this._receiver.cleanup(); + this._receiver = null; + } + removeAllListeners(this); + this.on('error', function() {}); // catch all errors after this + delete this._queue; +} + +function removeAllListeners(instance) { + if (isNodeV4) { + // node v4 doesn't *actually* remove all listeners globally, + // so we do that instead + instance._events = {}; + } + else instance.removeAllListeners(); +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/WebSocketServer.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/WebSocketServer.js new file mode 100644 index 00000000..da759f8b --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/WebSocketServer.js @@ -0,0 +1,460 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util') + , events = require('events') + , http = require('http') + , crypto = require('crypto') + , url = require('url') + , Options = require('options') + , WebSocket = require('./WebSocket') + , tls = require('tls') + , url = require('url'); + +/** + * WebSocket Server implementation + */ + +function WebSocketServer(options, callback) { + options = new Options({ + host: '0.0.0.0', + port: null, + server: null, + verifyClient: null, + handleProtocols: null, + path: null, + noServer: false, + disableHixie: false, + clientTracking: true + }).merge(options); + + if (!options.isDefinedAndNonNull('port') && !options.isDefinedAndNonNull('server') && !options.value.noServer) { + throw new TypeError('`port` or a `server` must be provided'); + } + + var self = this; + + if (options.isDefinedAndNonNull('port')) { + this._server = http.createServer(function (req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('Not implemented'); + }); + this._server.listen(options.value.port, options.value.host, callback); + this._closeServer = function() { self._server.close(); }; + } + else if (options.value.server) { + this._server = options.value.server; + if (options.value.path) { + // take note of the path, to avoid collisions when multiple websocket servers are + // listening on the same http server + if (this._server._webSocketPaths && options.value.server._webSocketPaths[options.value.path]) { + throw new Error('two instances of WebSocketServer cannot listen on the same http server path'); + } + if (typeof this._server._webSocketPaths !== 'object') { + this._server._webSocketPaths = {}; + } + this._server._webSocketPaths[options.value.path] = 1; + } + } + if (this._server) this._server.once('listening', function() { self.emit('listening'); }); + + if (typeof this._server != 'undefined') { + this._server.on('error', function(error) { + self.emit('error', error) + }); + this._server.on('upgrade', function(req, socket, upgradeHead) { + //copy upgradeHead to avoid retention of large slab buffers used in node core + var head = new Buffer(upgradeHead.length); + upgradeHead.copy(head); + + self.handleUpgrade(req, socket, head, function(client) { + self.emit('connection'+req.url, client); + self.emit('connection', client); + }); + }); + } + + this.options = options.value; + this.path = options.value.path; + this.clients = []; +} + +/** + * Inherits from EventEmitter. + */ + +util.inherits(WebSocketServer, events.EventEmitter); + +/** + * Immediately shuts down the connection. + * + * @api public + */ + +WebSocketServer.prototype.close = function() { + // terminate all associated clients + var error = null; + try { + for (var i = 0, l = this.clients.length; i < l; ++i) { + this.clients[i].terminate(); + } + } + catch (e) { + error = e; + } + + // remove path descriptor, if any + if (this.path && this._server._webSocketPaths) { + delete this._server._webSocketPaths[this.path]; + if (Object.keys(this._server._webSocketPaths).length == 0) { + delete this._server._webSocketPaths; + } + } + + // close the http server if it was internally created + try { + if (typeof this._closeServer !== 'undefined') { + this._closeServer(); + } + } + finally { + delete this._server; + } + if (error) throw error; +} + +/** + * Handle a HTTP Upgrade request. + * + * @api public + */ + +WebSocketServer.prototype.handleUpgrade = function(req, socket, upgradeHead, cb) { + // check for wrong path + if (this.options.path) { + var u = url.parse(req.url); + if (u && u.pathname !== this.options.path) return; + } + + if (typeof req.headers.upgrade === 'undefined' || req.headers.upgrade.toLowerCase() !== 'websocket') { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + if (req.headers['sec-websocket-key1']) handleHixieUpgrade.apply(this, arguments); + else handleHybiUpgrade.apply(this, arguments); +} + +module.exports = WebSocketServer; + +/** + * Entirely private apis, + * which may or may not be bound to a sepcific WebSocket instance. + */ + +function handleHybiUpgrade(req, socket, upgradeHead, cb) { + // handle premature socket errors + var errorHandler = function() { + try { socket.destroy(); } catch (e) {} + } + socket.on('error', errorHandler); + + // verify key presence + if (!req.headers['sec-websocket-key']) { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + // verify version + var version = parseInt(req.headers['sec-websocket-version']); + if ([8, 13].indexOf(version) === -1) { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + // verify protocol + var protocols = req.headers['sec-websocket-protocol']; + + // verify client + var origin = version < 13 ? + req.headers['sec-websocket-origin'] : + req.headers['origin']; + + // handler to call when the connection sequence completes + var self = this; + var completeHybiUpgrade2 = function(protocol) { + + // calc key + var key = req.headers['sec-websocket-key']; + var shasum = crypto.createHash('sha1'); + shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + key = shasum.digest('base64'); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: websocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Accept: ' + key + ]; + + if (typeof protocol != 'undefined') { + headers.push('Sec-WebSocket-Protocol: ' + protocol); + } + + // allows external modification/inspection of handshake headers + self.emit('headers', headers); + + socket.setTimeout(0); + socket.setNoDelay(true); + try { + socket.write(headers.concat('', '').join('\r\n')); + } + catch (e) { + // if the upgrade write fails, shut the connection down hard + try { socket.destroy(); } catch (e) {} + return; + } + + var client = new WebSocket([req, socket, upgradeHead], { + protocolVersion: version, + protocol: protocol + }); + + if (self.options.clientTracking) { + self.clients.push(client); + client.on('close', function() { + var index = self.clients.indexOf(client); + if (index != -1) { + self.clients.splice(index, 1); + } + }); + } + + // signal upgrade complete + socket.removeListener('error', errorHandler); + cb(client); + } + + // optionally call external protocol selection handler before + // calling completeHybiUpgrade2 + var completeHybiUpgrade1 = function() { + // choose from the sub-protocols + if (typeof self.options.handleProtocols == 'function') { + var protList = (protocols || "").split(/, */); + var callbackCalled = false; + var res = self.options.handleProtocols(protList, function(result, protocol) { + callbackCalled = true; + if (!result) abortConnection(socket, 404, 'Unauthorized') + else completeHybiUpgrade2(protocol); + }); + if (!callbackCalled) { + // the handleProtocols handler never called our callback + abortConnection(socket, 501, 'Could not process protocols'); + } + return; + } else { + if (typeof protocols !== 'undefined') { + completeHybiUpgrade2(protocols.split(/, */)[0]); + } + else { + completeHybiUpgrade2(); + } + } + } + + // optionally call external client verification handler + if (typeof this.options.verifyClient == 'function') { + var info = { + origin: origin, + secure: typeof req.connection.authorized !== 'undefined' || typeof req.connection.encrypted !== 'undefined', + req: req + }; + if (this.options.verifyClient.length == 2) { + this.options.verifyClient(info, function(result) { + if (!result) abortConnection(socket, 401, 'Unauthorized') + else completeHybiUpgrade1(); + }); + return; + } + else if (!this.options.verifyClient(info)) { + abortConnection(socket, 401, 'Unauthorized'); + return; + } + } + + completeHybiUpgrade1(); +} + +function handleHixieUpgrade(req, socket, upgradeHead, cb) { + // handle premature socket errors + var errorHandler = function() { + try { socket.destroy(); } catch (e) {} + } + socket.on('error', errorHandler); + + // bail if options prevent hixie + if (this.options.disableHixie) { + abortConnection(socket, 401, 'Hixie support disabled'); + return; + } + + // verify key presence + if (!req.headers['sec-websocket-key2']) { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + var origin = req.headers['origin'] + , self = this; + + // setup handshake completion to run after client has been verified + var onClientVerified = function() { + var wshost; + if (!req.headers['x-forwarded-host']) + wshost = req.headers.host; + else + wshost = req.headers['x-forwarded-host']; + var location = ((req.headers['x-forwarded-proto'] === 'https' || socket.encrypted) ? 'wss' : 'ws') + '://' + wshost + req.url + , protocol = req.headers['sec-websocket-protocol']; + + // handshake completion code to run once nonce has been successfully retrieved + var completeHandshake = function(nonce, rest) { + // calculate key + var k1 = req.headers['sec-websocket-key1'] + , k2 = req.headers['sec-websocket-key2'] + , md5 = crypto.createHash('md5'); + + [k1, k2].forEach(function (k) { + var n = parseInt(k.replace(/[^\d]/g, '')) + , spaces = k.replace(/[^ ]/g, '').length; + if (spaces === 0 || n % spaces !== 0){ + abortConnection(socket, 400, 'Bad Request'); + return; + } + n /= spaces; + md5.update(String.fromCharCode( + n >> 24 & 0xFF, + n >> 16 & 0xFF, + n >> 8 & 0xFF, + n & 0xFF)); + }); + md5.update(nonce.toString('binary')); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: WebSocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Location: ' + location + ]; + if (typeof protocol != 'undefined') headers.push('Sec-WebSocket-Protocol: ' + protocol); + if (typeof origin != 'undefined') headers.push('Sec-WebSocket-Origin: ' + origin); + + socket.setTimeout(0); + socket.setNoDelay(true); + try { + // merge header and hash buffer + var headerBuffer = new Buffer(headers.concat('', '').join('\r\n')); + var hashBuffer = new Buffer(md5.digest('binary'), 'binary'); + var handshakeBuffer = new Buffer(headerBuffer.length + hashBuffer.length); + headerBuffer.copy(handshakeBuffer, 0); + hashBuffer.copy(handshakeBuffer, headerBuffer.length); + + // do a single write, which - upon success - causes a new client websocket to be setup + socket.write(handshakeBuffer, 'binary', function(err) { + if (err) return; // do not create client if an error happens + var client = new WebSocket([req, socket, rest], { + protocolVersion: 'hixie-76', + protocol: protocol + }); + if (self.options.clientTracking) { + self.clients.push(client); + client.on('close', function() { + var index = self.clients.indexOf(client); + if (index != -1) { + self.clients.splice(index, 1); + } + }); + } + + // signal upgrade complete + socket.removeListener('error', errorHandler); + cb(client); + }); + } + catch (e) { + try { socket.destroy(); } catch (e) {} + return; + } + } + + // retrieve nonce + var nonceLength = 8; + if (upgradeHead && upgradeHead.length >= nonceLength) { + var nonce = upgradeHead.slice(0, nonceLength); + var rest = upgradeHead.length > nonceLength ? upgradeHead.slice(nonceLength) : null; + completeHandshake.call(self, nonce, rest); + } + else { + // nonce not present in upgradeHead, so we must wait for enough data + // data to arrive before continuing + var nonce = new Buffer(nonceLength); + upgradeHead.copy(nonce, 0); + var received = upgradeHead.length; + var rest = null; + var handler = function (data) { + var toRead = Math.min(data.length, nonceLength - received); + if (toRead === 0) return; + data.copy(nonce, received, 0, toRead); + received += toRead; + if (received == nonceLength) { + socket.removeListener('data', handler); + if (toRead < data.length) rest = data.slice(toRead); + completeHandshake.call(self, nonce, rest); + } + } + socket.on('data', handler); + } + } + + // verify client + if (typeof this.options.verifyClient == 'function') { + var info = { + origin: origin, + secure: typeof req.connection.authorized !== 'undefined' || typeof req.connection.encrypted !== 'undefined', + req: req + }; + if (this.options.verifyClient.length == 2) { + var self = this; + this.options.verifyClient(info, function(result) { + if (!result) abortConnection(socket, 401, 'Unauthorized') + else onClientVerified.apply(self); + }); + return; + } + else if (!this.options.verifyClient(info)) { + abortConnection(socket, 401, 'Unauthorized'); + return; + } + } + + // no client verification required + onClientVerified(); +} + +function abortConnection(socket, code, name) { + try { + var response = [ + 'HTTP/1.1 ' + code + ' ' + name, + 'Content-type: text/html' + ]; + socket.write(response.concat('', '').join('\r\n')); + } + catch (e) { /* ignore errors - we've aborted this connection */ } + finally { + // ensure that an early aborted connection is shut down completely + try { socket.destroy(); } catch (e) {} + } +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/browser.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/browser.js new file mode 100644 index 00000000..8d3a755c --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/browser.js @@ -0,0 +1,43 @@ + +/** + * Module dependencies. + */ + +var global = (function() { return this; })(); + +/** + * WebSocket constructor. + */ + +var WebSocket = global.WebSocket || global.MozWebSocket; + +/** + * Module exports. + */ + +module.exports = WebSocket ? ws : null; + +/** + * WebSocket constructor. + * + * The third `opts` options object gets ignored in web browsers, since it's + * non-standard, and throws a TypeError if passed to the constructor. + * See: https://github.com/einaros/ws/issues/227 + * + * @param {String} uri + * @param {Array} protocols (optional) + * @param {Object) opts (optional) + * @api public + */ + +function ws(uri, protocols, opts) { + var instance; + if (protocols) { + instance = new WebSocket(uri, protocols); + } else { + instance = new WebSocket(uri); + } + return instance; +} + +if (WebSocket) ws.prototype = WebSocket.prototype; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/.npmignore b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/.npmignore new file mode 100644 index 00000000..f1250e58 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/.travis.yml b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/.travis.yml new file mode 100644 index 00000000..f1d0f13c --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.4 + - 0.6 diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/History.md b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/History.md new file mode 100644 index 00000000..4961d2e2 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/History.md @@ -0,0 +1,107 @@ + +0.6.1 / 2012-06-01 +================== + + * Added: append (yes or no) on confirmation + * Added: allow node.js v0.7.x + +0.6.0 / 2012-04-10 +================== + + * Added `.prompt(obj, callback)` support. Closes #49 + * Added default support to .choose(). Closes #41 + * Fixed the choice example + +0.5.1 / 2011-12-20 +================== + + * Fixed `password()` for recent nodes. Closes #36 + +0.5.0 / 2011-12-04 +================== + + * Added sub-command option support [itay] + +0.4.3 / 2011-12-04 +================== + + * Fixed custom help ordering. Closes #32 + +0.4.2 / 2011-11-24 +================== + + * Added travis support + * Fixed: line-buffered input automatically trimmed. Closes #31 + +0.4.1 / 2011-11-18 +================== + + * Removed listening for "close" on --help + +0.4.0 / 2011-11-15 +================== + + * Added support for `--`. Closes #24 + +0.3.3 / 2011-11-14 +================== + + * Fixed: wait for close event when writing help info [Jerry Hamlet] + +0.3.2 / 2011-11-01 +================== + + * Fixed long flag definitions with values [felixge] + +0.3.1 / 2011-10-31 +================== + + * Changed `--version` short flag to `-V` from `-v` + * Changed `.version()` so it's configurable [felixge] + +0.3.0 / 2011-10-31 +================== + + * Added support for long flags only. Closes #18 + +0.2.1 / 2011-10-24 +================== + + * "node": ">= 0.4.x < 0.7.0". Closes #20 + +0.2.0 / 2011-09-26 +================== + + * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs] + +0.1.0 / 2011-08-24 +================== + + * Added support for custom `--help` output + +0.0.5 / 2011-08-18 +================== + + * Changed: when the user enters nothing prompt for password again + * Fixed issue with passwords beginning with numbers [NuckChorris] + +0.0.4 / 2011-08-15 +================== + + * Fixed `Commander#args` + +0.0.3 / 2011-08-15 +================== + + * Added default option value support + +0.0.2 / 2011-08-15 +================== + + * Added mask support to `Command#password(str[, mask], fn)` + * Added `Command#password(str, fn)` + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/Makefile b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/Makefile new file mode 100644 index 00000000..00746255 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/Makefile @@ -0,0 +1,7 @@ + +TESTS = $(shell find test/test.*.js) + +test: + @./test/run $(TESTS) + +.PHONY: test \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/Readme.md b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/Readme.md new file mode 100644 index 00000000..b8328c37 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/Readme.md @@ -0,0 +1,262 @@ +# Commander.js + + The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander). + + [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js) + +## Installation + + $ npm install commander + +## Option parsing + + Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .version('0.0.1') + .option('-p, --peppers', 'Add peppers') + .option('-P, --pineapple', 'Add pineapple') + .option('-b, --bbq', 'Add bbq sauce') + .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') + .parse(process.argv); + +console.log('you ordered a pizza with:'); +if (program.peppers) console.log(' - peppers'); +if (program.pineapple) console.log(' - pineappe'); +if (program.bbq) console.log(' - bbq'); +console.log(' - %s cheese', program.cheese); +``` + + Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. + +## Automated --help + + The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: + +``` + $ ./examples/pizza --help + + Usage: pizza [options] + + Options: + + -V, --version output the version number + -p, --peppers Add peppers + -P, --pineapple Add pineappe + -b, --bbq Add bbq sauce + -c, --cheese Add the specified type of cheese [marble] + -h, --help output usage information + +``` + +## Coercion + +```js +function range(val) { + return val.split('..').map(Number); +} + +function list(val) { + return val.split(','); +} + +program + .version('0.0.1') + .usage('[options] ') + .option('-i, --integer ', 'An integer argument', parseInt) + .option('-f, --float ', 'A float argument', parseFloat) + .option('-r, --range ..', 'A range', range) + .option('-l, --list ', 'A list', list) + .option('-o, --optional [value]', 'An optional value') + .parse(process.argv); + +console.log(' int: %j', program.integer); +console.log(' float: %j', program.float); +console.log(' optional: %j', program.optional); +program.range = program.range || []; +console.log(' range: %j..%j', program.range[0], program.range[1]); +console.log(' list: %j', program.list); +console.log(' args: %j', program.args); +``` + +## Custom help + + You can display arbitrary `-h, --help` information + by listening for "--help". Commander will automatically + exit once you are done so that the remainder of your program + does not execute causing undesired behaviours, for example + in the following executable "stuff" will not output when + `--help` is used. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('../'); + +function list(val) { + return val.split(',').map(Number); +} + +program + .version('0.0.1') + .option('-f, --foo', 'enable some foo') + .option('-b, --bar', 'enable some bar') + .option('-B, --baz', 'enable some baz'); + +// must be before .parse() since +// node's emit() is immediate + +program.on('--help', function(){ + console.log(' Examples:'); + console.log(''); + console.log(' $ custom-help --help'); + console.log(' $ custom-help -h'); + console.log(''); +}); + +program.parse(process.argv); + +console.log('stuff'); +``` + +yielding the following help output: + +``` + +Usage: custom-help [options] + +Options: + + -h, --help output usage information + -V, --version output the version number + -f, --foo enable some foo + -b, --bar enable some bar + -B, --baz enable some baz + +Examples: + + $ custom-help --help + $ custom-help -h + +``` + +## .prompt(msg, fn) + + Single-line prompt: + +```js +program.prompt('name: ', function(name){ + console.log('hi %s', name); +}); +``` + + Multi-line prompt: + +```js +program.prompt('description:', function(name){ + console.log('hi %s', name); +}); +``` + + Coercion: + +```js +program.prompt('Age: ', Number, function(age){ + console.log('age: %j', age); +}); +``` + +```js +program.prompt('Birthdate: ', Date, function(date){ + console.log('date: %s', date); +}); +``` + +## .password(msg[, mask], fn) + +Prompt for password without echoing: + +```js +program.password('Password: ', function(pass){ + console.log('got "%s"', pass); + process.stdin.destroy(); +}); +``` + +Prompt for password with mask char "*": + +```js +program.password('Password: ', '*', function(pass){ + console.log('got "%s"', pass); + process.stdin.destroy(); +}); +``` + +## .confirm(msg, fn) + + Confirm with the given `msg`: + +```js +program.confirm('continue? ', function(ok){ + console.log(' got %j', ok); +}); +``` + +## .choose(list, fn) + + Let the user choose from a `list`: + +```js +var list = ['tobi', 'loki', 'jane', 'manny', 'luna']; + +console.log('Choose the coolest pet:'); +program.choose(list, function(i){ + console.log('you chose %d "%s"', i, list[i]); +}); +``` + +## Links + + - [API documentation](http://visionmedia.github.com/commander.js/) + - [ascii tables](https://github.com/LearnBoost/cli-table) + - [progress bars](https://github.com/visionmedia/node-progress) + - [more progress bars](https://github.com/substack/node-multimeter) + - [examples](https://github.com/visionmedia/commander.js/tree/master/examples) + +## License + +(The MIT License) + +Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> + +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: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +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. \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/index.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/index.js new file mode 100644 index 00000000..06ec1e4b --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/commander'); \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/lib/commander.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/lib/commander.js new file mode 100644 index 00000000..5ba87ebb --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/lib/commander.js @@ -0,0 +1,1026 @@ + +/*! + * commander + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , path = require('path') + , tty = require('tty') + , basename = path.basename; + +/** + * Expose the root command. + */ + +exports = module.exports = new Command; + +/** + * Expose `Command`. + */ + +exports.Command = Command; + +/** + * Expose `Option`. + */ + +exports.Option = Option; + +/** + * Initialize a new `Option` with the given `flags` and `description`. + * + * @param {String} flags + * @param {String} description + * @api public + */ + +function Option(flags, description) { + this.flags = flags; + this.required = ~flags.indexOf('<'); + this.optional = ~flags.indexOf('['); + this.bool = !~flags.indexOf('-no-'); + flags = flags.split(/[ ,|]+/); + if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift(); + this.long = flags.shift(); + this.description = description; +} + +/** + * Return option name. + * + * @return {String} + * @api private + */ + +Option.prototype.name = function(){ + return this.long + .replace('--', '') + .replace('no-', ''); +}; + +/** + * Check if `arg` matches the short or long flag. + * + * @param {String} arg + * @return {Boolean} + * @api private + */ + +Option.prototype.is = function(arg){ + return arg == this.short + || arg == this.long; +}; + +/** + * Initialize a new `Command`. + * + * @param {String} name + * @api public + */ + +function Command(name) { + this.commands = []; + this.options = []; + this.args = []; + this.name = name; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Command.prototype.__proto__ = EventEmitter.prototype; + +/** + * Add command `name`. + * + * The `.action()` callback is invoked when the + * command `name` is specified via __ARGV__, + * and the remaining arguments are applied to the + * function for access. + * + * When the `name` is "*" an un-matched command + * will be passed as the first arg, followed by + * the rest of __ARGV__ remaining. + * + * Examples: + * + * program + * .version('0.0.1') + * .option('-C, --chdir ', 'change the working directory') + * .option('-c, --config ', 'set config path. defaults to ./deploy.conf') + * .option('-T, --no-tests', 'ignore test hook') + * + * program + * .command('setup') + * .description('run remote setup commands') + * .action(function(){ + * console.log('setup'); + * }); + * + * program + * .command('exec ') + * .description('run the given remote command') + * .action(function(cmd){ + * console.log('exec "%s"', cmd); + * }); + * + * program + * .command('*') + * .description('deploy the given env') + * .action(function(env){ + * console.log('deploying "%s"', env); + * }); + * + * program.parse(process.argv); + * + * @param {String} name + * @return {Command} the new command + * @api public + */ + +Command.prototype.command = function(name){ + var args = name.split(/ +/); + var cmd = new Command(args.shift()); + this.commands.push(cmd); + cmd.parseExpectedArgs(args); + cmd.parent = this; + return cmd; +}; + +/** + * Parse expected `args`. + * + * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`. + * + * @param {Array} args + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parseExpectedArgs = function(args){ + if (!args.length) return; + var self = this; + args.forEach(function(arg){ + switch (arg[0]) { + case '<': + self.args.push({ required: true, name: arg.slice(1, -1) }); + break; + case '[': + self.args.push({ required: false, name: arg.slice(1, -1) }); + break; + } + }); + return this; +}; + +/** + * Register callback `fn` for the command. + * + * Examples: + * + * program + * .command('help') + * .description('display verbose help') + * .action(function(){ + * // output help here + * }); + * + * @param {Function} fn + * @return {Command} for chaining + * @api public + */ + +Command.prototype.action = function(fn){ + var self = this; + this.parent.on(this.name, function(args, unknown){ + // Parse any so-far unknown options + unknown = unknown || []; + var parsed = self.parseOptions(unknown); + + // Output help if necessary + outputHelpIfNecessary(self, parsed.unknown); + + // If there are still any unknown options, then we simply + // die, unless someone asked for help, in which case we give it + // to them, and then we die. + if (parsed.unknown.length > 0) { + self.unknownOption(parsed.unknown[0]); + } + + self.args.forEach(function(arg, i){ + if (arg.required && null == args[i]) { + self.missingArgument(arg.name); + } + }); + + // Always append ourselves to the end of the arguments, + // to make sure we match the number of arguments the user + // expects + if (self.args.length) { + args[self.args.length] = self; + } else { + args.push(self); + } + + fn.apply(this, args); + }); + return this; +}; + +/** + * Define option with `flags`, `description` and optional + * coercion `fn`. + * + * The `flags` string should contain both the short and long flags, + * separated by comma, a pipe or space. The following are all valid + * all will output this way when `--help` is used. + * + * "-p, --pepper" + * "-p|--pepper" + * "-p --pepper" + * + * Examples: + * + * // simple boolean defaulting to false + * program.option('-p, --pepper', 'add pepper'); + * + * --pepper + * program.pepper + * // => Boolean + * + * // simple boolean defaulting to false + * program.option('-C, --no-cheese', 'remove cheese'); + * + * program.cheese + * // => true + * + * --no-cheese + * program.cheese + * // => true + * + * // required argument + * program.option('-C, --chdir ', 'change the working directory'); + * + * --chdir /tmp + * program.chdir + * // => "/tmp" + * + * // optional argument + * program.option('-c, --cheese [type]', 'add cheese [marble]'); + * + * @param {String} flags + * @param {String} description + * @param {Function|Mixed} fn or default + * @param {Mixed} defaultValue + * @return {Command} for chaining + * @api public + */ + +Command.prototype.option = function(flags, description, fn, defaultValue){ + var self = this + , option = new Option(flags, description) + , oname = option.name() + , name = camelcase(oname); + + // default as 3rd arg + if ('function' != typeof fn) defaultValue = fn, fn = null; + + // preassign default value only for --no-*, [optional], or + if (false == option.bool || option.optional || option.required) { + // when --no-* we make sure default is true + if (false == option.bool) defaultValue = true; + // preassign only if we have a default + if (undefined !== defaultValue) self[name] = defaultValue; + } + + // register the option + this.options.push(option); + + // when it's passed assign the value + // and conditionally invoke the callback + this.on(oname, function(val){ + // coercion + if (null != val && fn) val = fn(val); + + // unassigned or bool + if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { + // if no value, bool true, and we have a default, then use it! + if (null == val) { + self[name] = option.bool + ? defaultValue || true + : false; + } else { + self[name] = val; + } + } else if (null !== val) { + // reassign + self[name] = val; + } + }); + + return this; +}; + +/** + * Parse `argv`, settings options and invoking commands when defined. + * + * @param {Array} argv + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parse = function(argv){ + // store raw args + this.rawArgs = argv; + + // guess name + if (!this.name) this.name = basename(argv[1]); + + // process argv + var parsed = this.parseOptions(this.normalize(argv.slice(2))); + this.args = parsed.args; + return this.parseArgs(this.args, parsed.unknown); +}; + +/** + * Normalize `args`, splitting joined short flags. For example + * the arg "-abc" is equivalent to "-a -b -c". + * + * @param {Array} args + * @return {Array} + * @api private + */ + +Command.prototype.normalize = function(args){ + var ret = [] + , arg; + + for (var i = 0, len = args.length; i < len; ++i) { + arg = args[i]; + if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) { + arg.slice(1).split('').forEach(function(c){ + ret.push('-' + c); + }); + } else { + ret.push(arg); + } + } + + return ret; +}; + +/** + * Parse command `args`. + * + * When listener(s) are available those + * callbacks are invoked, otherwise the "*" + * event is emitted and those actions are invoked. + * + * @param {Array} args + * @return {Command} for chaining + * @api private + */ + +Command.prototype.parseArgs = function(args, unknown){ + var cmds = this.commands + , len = cmds.length + , name; + + if (args.length) { + name = args[0]; + if (this.listeners(name).length) { + this.emit(args.shift(), args, unknown); + } else { + this.emit('*', args); + } + } else { + outputHelpIfNecessary(this, unknown); + + // If there were no args and we have unknown options, + // then they are extraneous and we need to error. + if (unknown.length > 0) { + this.unknownOption(unknown[0]); + } + } + + return this; +}; + +/** + * Return an option matching `arg` if any. + * + * @param {String} arg + * @return {Option} + * @api private + */ + +Command.prototype.optionFor = function(arg){ + for (var i = 0, len = this.options.length; i < len; ++i) { + if (this.options[i].is(arg)) { + return this.options[i]; + } + } +}; + +/** + * Parse options from `argv` returning `argv` + * void of these options. + * + * @param {Array} argv + * @return {Array} + * @api public + */ + +Command.prototype.parseOptions = function(argv){ + var args = [] + , len = argv.length + , literal + , option + , arg; + + var unknownOptions = []; + + // parse options + for (var i = 0; i < len; ++i) { + arg = argv[i]; + + // literal args after -- + if ('--' == arg) { + literal = true; + continue; + } + + if (literal) { + args.push(arg); + continue; + } + + // find matching Option + option = this.optionFor(arg); + + // option is defined + if (option) { + // requires arg + if (option.required) { + arg = argv[++i]; + if (null == arg) return this.optionMissingArgument(option); + if ('-' == arg[0]) return this.optionMissingArgument(option, arg); + this.emit(option.name(), arg); + // optional arg + } else if (option.optional) { + arg = argv[i+1]; + if (null == arg || '-' == arg[0]) { + arg = null; + } else { + ++i; + } + this.emit(option.name(), arg); + // bool + } else { + this.emit(option.name()); + } + continue; + } + + // looks like an option + if (arg.length > 1 && '-' == arg[0]) { + unknownOptions.push(arg); + + // If the next argument looks like it might be + // an argument for this option, we pass it on. + // If it isn't, then it'll simply be ignored + if (argv[i+1] && '-' != argv[i+1][0]) { + unknownOptions.push(argv[++i]); + } + continue; + } + + // arg + args.push(arg); + } + + return { args: args, unknown: unknownOptions }; +}; + +/** + * Argument `name` is missing. + * + * @param {String} name + * @api private + */ + +Command.prototype.missingArgument = function(name){ + console.error(); + console.error(" error: missing required argument `%s'", name); + console.error(); + process.exit(1); +}; + +/** + * `Option` is missing an argument, but received `flag` or nothing. + * + * @param {String} option + * @param {String} flag + * @api private + */ + +Command.prototype.optionMissingArgument = function(option, flag){ + console.error(); + if (flag) { + console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); + } else { + console.error(" error: option `%s' argument missing", option.flags); + } + console.error(); + process.exit(1); +}; + +/** + * Unknown option `flag`. + * + * @param {String} flag + * @api private + */ + +Command.prototype.unknownOption = function(flag){ + console.error(); + console.error(" error: unknown option `%s'", flag); + console.error(); + process.exit(1); +}; + +/** + * Set the program version to `str`. + * + * This method auto-registers the "-V, --version" flag + * which will print the version number when passed. + * + * @param {String} str + * @param {String} flags + * @return {Command} for chaining + * @api public + */ + +Command.prototype.version = function(str, flags){ + if (0 == arguments.length) return this._version; + this._version = str; + flags = flags || '-V, --version'; + this.option(flags, 'output the version number'); + this.on('version', function(){ + console.log(str); + process.exit(0); + }); + return this; +}; + +/** + * Set the description `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.description = function(str){ + if (0 == arguments.length) return this._description; + this._description = str; + return this; +}; + +/** + * Set / get the command usage `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.usage = function(str){ + var args = this.args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }); + + var usage = '[options' + + (this.commands.length ? '] [command' : '') + + ']' + + (this.args.length ? ' ' + args : ''); + if (0 == arguments.length) return this._usage || usage; + this._usage = str; + + return this; +}; + +/** + * Return the largest option length. + * + * @return {Number} + * @api private + */ + +Command.prototype.largestOptionLength = function(){ + return this.options.reduce(function(max, option){ + return Math.max(max, option.flags.length); + }, 0); +}; + +/** + * Return help for options. + * + * @return {String} + * @api private + */ + +Command.prototype.optionHelp = function(){ + var width = this.largestOptionLength(); + + // Prepend the help information + return [pad('-h, --help', width) + ' ' + 'output usage information'] + .concat(this.options.map(function(option){ + return pad(option.flags, width) + + ' ' + option.description; + })) + .join('\n'); +}; + +/** + * Return command help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.commandHelp = function(){ + if (!this.commands.length) return ''; + return [ + '' + , ' Commands:' + , '' + , this.commands.map(function(cmd){ + var args = cmd.args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }).join(' '); + + return cmd.name + + (cmd.options.length + ? ' [options]' + : '') + ' ' + args + + (cmd.description() + ? '\n' + cmd.description() + : ''); + }).join('\n\n').replace(/^/gm, ' ') + , '' + ].join('\n'); +}; + +/** + * Return program help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.helpInformation = function(){ + return [ + '' + , ' Usage: ' + this.name + ' ' + this.usage() + , '' + this.commandHelp() + , ' Options:' + , '' + , '' + this.optionHelp().replace(/^/gm, ' ') + , '' + , '' + ].join('\n'); +}; + +/** + * Prompt for a `Number`. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptForNumber = function(str, fn){ + var self = this; + this.promptSingleLine(str, function parseNumber(val){ + val = Number(val); + if (isNaN(val)) return self.promptSingleLine(str + '(must be a number) ', parseNumber); + fn(val); + }); +}; + +/** + * Prompt for a `Date`. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptForDate = function(str, fn){ + var self = this; + this.promptSingleLine(str, function parseDate(val){ + val = new Date(val); + if (isNaN(val.getTime())) return self.promptSingleLine(str + '(must be a date) ', parseDate); + fn(val); + }); +}; + +/** + * Single-line prompt. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptSingleLine = function(str, fn){ + if ('function' == typeof arguments[2]) { + return this['promptFor' + (fn.name || fn)](str, arguments[2]); + } + + process.stdout.write(str); + process.stdin.setEncoding('utf8'); + process.stdin.once('data', function(val){ + fn(val.trim()); + }).resume(); +}; + +/** + * Multi-line prompt. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptMultiLine = function(str, fn){ + var buf = []; + console.log(str); + process.stdin.setEncoding('utf8'); + process.stdin.on('data', function(val){ + if ('\n' == val || '\r\n' == val) { + process.stdin.removeAllListeners('data'); + fn(buf.join('\n')); + } else { + buf.push(val.trimRight()); + } + }).resume(); +}; + +/** + * Prompt `str` and callback `fn(val)` + * + * Commander supports single-line and multi-line prompts. + * To issue a single-line prompt simply add white-space + * to the end of `str`, something like "name: ", whereas + * for a multi-line prompt omit this "description:". + * + * + * Examples: + * + * program.prompt('Username: ', function(name){ + * console.log('hi %s', name); + * }); + * + * program.prompt('Description:', function(desc){ + * console.log('description was "%s"', desc.trim()); + * }); + * + * @param {String|Object} str + * @param {Function} fn + * @api public + */ + +Command.prototype.prompt = function(str, fn){ + var self = this; + + if ('string' == typeof str) { + if (/ $/.test(str)) return this.promptSingleLine.apply(this, arguments); + this.promptMultiLine(str, fn); + } else { + var keys = Object.keys(str) + , obj = {}; + + function next() { + var key = keys.shift() + , label = str[key]; + + if (!key) return fn(obj); + self.prompt(label, function(val){ + obj[key] = val; + next(); + }); + } + + next(); + } +}; + +/** + * Prompt for password with `str`, `mask` char and callback `fn(val)`. + * + * The mask string defaults to '', aka no output is + * written while typing, you may want to use "*" etc. + * + * Examples: + * + * program.password('Password: ', function(pass){ + * console.log('got "%s"', pass); + * process.stdin.destroy(); + * }); + * + * program.password('Password: ', '*', function(pass){ + * console.log('got "%s"', pass); + * process.stdin.destroy(); + * }); + * + * @param {String} str + * @param {String} mask + * @param {Function} fn + * @api public + */ + +Command.prototype.password = function(str, mask, fn){ + var self = this + , buf = ''; + + // default mask + if ('function' == typeof mask) { + fn = mask; + mask = ''; + } + + process.stdin.resume(); + tty.setRawMode(true); + process.stdout.write(str); + + // keypress + process.stdin.on('keypress', function(c, key){ + if (key && 'enter' == key.name) { + console.log(); + process.stdin.removeAllListeners('keypress'); + tty.setRawMode(false); + if (!buf.trim().length) return self.password(str, mask, fn); + fn(buf); + return; + } + + if (key && key.ctrl && 'c' == key.name) { + console.log('%s', buf); + process.exit(); + } + + process.stdout.write(mask); + buf += c; + }).resume(); +}; + +/** + * Confirmation prompt with `str` and callback `fn(bool)` + * + * Examples: + * + * program.confirm('continue? ', function(ok){ + * console.log(' got %j', ok); + * process.stdin.destroy(); + * }); + * + * @param {String} str + * @param {Function} fn + * @api public + */ + + +Command.prototype.confirm = function(str, fn, verbose){ + var self = this; + this.prompt(str, function(ok){ + if (!ok.trim()) { + if (!verbose) str += '(yes or no) '; + return self.confirm(str, fn, true); + } + fn(parseBool(ok)); + }); +}; + +/** + * Choice prompt with `list` of items and callback `fn(index, item)` + * + * Examples: + * + * var list = ['tobi', 'loki', 'jane', 'manny', 'luna']; + * + * console.log('Choose the coolest pet:'); + * program.choose(list, function(i){ + * console.log('you chose %d "%s"', i, list[i]); + * process.stdin.destroy(); + * }); + * + * @param {Array} list + * @param {Number|Function} index or fn + * @param {Function} fn + * @api public + */ + +Command.prototype.choose = function(list, index, fn){ + var self = this + , hasDefault = 'number' == typeof index; + + if (!hasDefault) { + fn = index; + index = null; + } + + list.forEach(function(item, i){ + if (hasDefault && i == index) { + console.log('* %d) %s', i + 1, item); + } else { + console.log(' %d) %s', i + 1, item); + } + }); + + function again() { + self.prompt(' : ', function(val){ + val = parseInt(val, 10) - 1; + if (hasDefault && isNaN(val)) val = index; + + if (null == list[val]) { + again(); + } else { + fn(val, list[val]); + } + }); + } + + again(); +}; + +/** + * Camel-case the given `flag` + * + * @param {String} flag + * @return {String} + * @api private + */ + +function camelcase(flag) { + return flag.split('-').reduce(function(str, word){ + return str + word[0].toUpperCase() + word.slice(1); + }); +} + +/** + * Parse a boolean `str`. + * + * @param {String} str + * @return {Boolean} + * @api private + */ + +function parseBool(str) { + return /^y|yes|ok|true$/i.test(str); +} + +/** + * Pad `str` to `width`. + * + * @param {String} str + * @param {Number} width + * @return {String} + * @api private + */ + +function pad(str, width) { + var len = Math.max(0, width - str.length); + return str + Array(len + 1).join(' '); +} + +/** + * Output help information if necessary + * + * @param {Command} command to output help for + * @param {Array} array of options to search for -h or --help + * @api private + */ + +function outputHelpIfNecessary(cmd, options) { + options = options || []; + for (var i = 0; i < options.length; i++) { + if (options[i] == '--help' || options[i] == '-h') { + process.stdout.write(cmd.helpInformation()); + cmd.emit('--help'); + process.exit(0); + } + } +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/package.json new file mode 100644 index 00000000..9936f7d7 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/package.json @@ -0,0 +1,39 @@ +{ + "name": "commander", + "version": "0.6.1", + "description": "the complete solution for node.js command-line programs", + "keywords": [ + "command", + "option", + "parser", + "prompt", + "stdin" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "repository": { + "type": "git", + "url": "https://github.com/visionmedia/commander.js.git" + }, + "dependencies": {}, + "devDependencies": { + "should": ">= 0.0.1" + }, + "scripts": { + "test": "make test" + }, + "main": "index", + "engines": { + "node": ">= 0.4.x" + }, + "readme": "# Commander.js\n\n The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).\n\n [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)\n\n## Installation\n\n $ npm install commander\n\n## Option parsing\n\n Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('commander');\n\nprogram\n .version('0.0.1')\n .option('-p, --peppers', 'Add peppers')\n .option('-P, --pineapple', 'Add pineapple')\n .option('-b, --bbq', 'Add bbq sauce')\n .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')\n .parse(process.argv);\n\nconsole.log('you ordered a pizza with:');\nif (program.peppers) console.log(' - peppers');\nif (program.pineapple) console.log(' - pineappe');\nif (program.bbq) console.log(' - bbq');\nconsole.log(' - %s cheese', program.cheese);\n```\n\n Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as \"--template-engine\" are camel-cased, becoming `program.templateEngine` etc.\n\n## Automated --help\n\n The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:\n\n``` \n $ ./examples/pizza --help\n\n Usage: pizza [options]\n\n Options:\n\n -V, --version output the version number\n -p, --peppers Add peppers\n -P, --pineapple Add pineappe\n -b, --bbq Add bbq sauce\n -c, --cheese Add the specified type of cheese [marble]\n -h, --help output usage information\n\n```\n\n## Coercion\n\n```js\nfunction range(val) {\n return val.split('..').map(Number);\n}\n\nfunction list(val) {\n return val.split(',');\n}\n\nprogram\n .version('0.0.1')\n .usage('[options] ')\n .option('-i, --integer ', 'An integer argument', parseInt)\n .option('-f, --float ', 'A float argument', parseFloat)\n .option('-r, --range ..', 'A range', range)\n .option('-l, --list ', 'A list', list)\n .option('-o, --optional [value]', 'An optional value')\n .parse(process.argv);\n\nconsole.log(' int: %j', program.integer);\nconsole.log(' float: %j', program.float);\nconsole.log(' optional: %j', program.optional);\nprogram.range = program.range || [];\nconsole.log(' range: %j..%j', program.range[0], program.range[1]);\nconsole.log(' list: %j', program.list);\nconsole.log(' args: %j', program.args);\n```\n\n## Custom help\n\n You can display arbitrary `-h, --help` information\n by listening for \"--help\". Commander will automatically\n exit once you are done so that the remainder of your program\n does not execute causing undesired behaviours, for example\n in the following executable \"stuff\" will not output when\n `--help` is used.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('../');\n\nfunction list(val) {\n return val.split(',').map(Number);\n}\n\nprogram\n .version('0.0.1')\n .option('-f, --foo', 'enable some foo')\n .option('-b, --bar', 'enable some bar')\n .option('-B, --baz', 'enable some baz');\n\n// must be before .parse() since\n// node's emit() is immediate\n\nprogram.on('--help', function(){\n console.log(' Examples:');\n console.log('');\n console.log(' $ custom-help --help');\n console.log(' $ custom-help -h');\n console.log('');\n});\n\nprogram.parse(process.argv);\n\nconsole.log('stuff');\n```\n\nyielding the following help output:\n\n```\n\nUsage: custom-help [options]\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -f, --foo enable some foo\n -b, --bar enable some bar\n -B, --baz enable some baz\n\nExamples:\n\n $ custom-help --help\n $ custom-help -h\n\n```\n\n## .prompt(msg, fn)\n\n Single-line prompt:\n\n```js\nprogram.prompt('name: ', function(name){\n console.log('hi %s', name);\n});\n```\n\n Multi-line prompt:\n\n```js\nprogram.prompt('description:', function(name){\n console.log('hi %s', name);\n});\n```\n\n Coercion:\n\n```js\nprogram.prompt('Age: ', Number, function(age){\n console.log('age: %j', age);\n});\n```\n\n```js\nprogram.prompt('Birthdate: ', Date, function(date){\n console.log('date: %s', date);\n});\n```\n\n## .password(msg[, mask], fn)\n\nPrompt for password without echoing:\n\n```js\nprogram.password('Password: ', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\nPrompt for password with mask char \"*\":\n\n```js\nprogram.password('Password: ', '*', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\n## .confirm(msg, fn)\n\n Confirm with the given `msg`:\n\n```js\nprogram.confirm('continue? ', function(ok){\n console.log(' got %j', ok);\n});\n```\n\n## .choose(list, fn)\n\n Let the user choose from a `list`:\n\n```js\nvar list = ['tobi', 'loki', 'jane', 'manny', 'luna'];\n\nconsole.log('Choose the coolest pet:');\nprogram.choose(list, function(i){\n console.log('you chose %d \"%s\"', i, list[i]);\n});\n```\n\n## Links\n\n - [API documentation](http://visionmedia.github.com/commander.js/)\n - [ascii tables](https://github.com/LearnBoost/cli-table)\n - [progress bars](https://github.com/visionmedia/node-progress)\n - [more progress bars](https://github.com/substack/node-multimeter)\n - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/commander.js/issues" + }, + "homepage": "https://github.com/visionmedia/commander.js", + "_id": "commander@0.6.1", + "_from": "commander@~0.6.1" +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/.index.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/.index.js new file mode 100644 index 00000000..68da1f34 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/.index.js @@ -0,0 +1 @@ +//noop \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/LICENSE b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/LICENSE new file mode 100644 index 00000000..352c2874 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/LICENSE @@ -0,0 +1,43 @@ +Copyright 2013, NAN contributors: + - Rod Vagg + - Benjamin Byholm + - Trevor Norris +(the "Original Author") +All rights reserved. + +MIT +no-false-attribs License + +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: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +Distributions of all or part of the Software intended to be used +by the recipients as they would use the unmodified Software, +containing modifications that substantially alter, remove, or +disable functionality of the Software, outside of the documented +configuration mechanisms provided by the Software, shall be +modified such that the Original Author's bug reporting email +addresses and urls are either replaced with the contact information +of the parties responsible for the changes, or removed entirely. + +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. + + +Except where noted, this license applies to any and all software +programs and associated documentation files created by the +Original Author, when distributed with the Software. diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/README.md b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/README.md new file mode 100644 index 00000000..6ba57f78 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/README.md @@ -0,0 +1,705 @@ +Native Abstractions for Node.js +=============================== + +**A header file filled with macro and utility goodness for making addon development for Node.js easier across versions 0.8, 0.10 and 0.11, and eventually 0.12.** + +***Current version: 0.3.2*** *(See [nan.h](https://github.com/rvagg/nan/blob/master/nan.h) for changelog)* + +[![NPM](https://nodei.co/npm/nan.png?downloads=true&stars=true)](https://nodei.co/npm/nan/) [![NPM](https://nodei.co/npm-dl/nan.png?months=6)](https://nodei.co/npm/nan/) + +Thanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.11/0.12, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js addons without having to inspect `NODE_MODULE_VERSION` and get yourself into a macro-tangle. + +This project also contains some helper utilities that make addon development a bit more pleasant. + + * **[Usage](#usage)** + * **[Example](#example)** + * **[API](#api)** + + +## Usage + +Simply add **NAN** as a dependency in the *package.json* of your Node addon: + +```js +"dependencies": { + ... + "nan" : "~0.3.1" + ... +} +``` + +Pull in the path to **NAN** in your *binding.gyp* so that you can use `#include "nan.h"` in your *.cpp*: + +```js +"include_dirs" : [ + ... + "` when compiling your addon. + + +## Example + +See **[LevelDOWN](https://github.com/rvagg/node-leveldown/pull/48)** for a full example of **NAN** in use. + +For a simpler example, see the **[async pi estimation example](https://github.com/rvagg/nan/tree/master/examples/async_pi_estimate)** in the examples directory for full code and an explanation of what this Monte Carlo Pi estimation example does. Below are just some parts of the full example that illustrate the use of **NAN**. + +Compare to the current 0.10 version of this example, found in the [node-addon-examples](https://github.com/rvagg/node-addon-examples/tree/master/9_async_work) repository and also a 0.11 version of the same found [here](https://github.com/kkoopa/node-addon-examples/tree/5c01f58fc993377a567812597e54a83af69686d7/9_async_work). + +Note that there is no embedded version sniffing going on here and also the async work is made much simpler, see below for details on the `NanAsyncWorker` class. + +```c++ +// addon.cc +#include +#include "nan.h" +// ... + +using namespace v8; + +void InitAll(Handle exports) { + exports->Set(NanSymbol("calculateSync"), + FunctionTemplate::New(CalculateSync)->GetFunction()); + + exports->Set(NanSymbol("calculateAsync"), + FunctionTemplate::New(CalculateAsync)->GetFunction()); +} + +NODE_MODULE(addon, InitAll) +``` + +```c++ +// sync.h +#include +#include "nan.h" + +NAN_METHOD(CalculateSync); +``` + +```c++ +// sync.cc +#include +#include "nan.h" +#include "sync.h" +// ... + +using namespace v8; + +// Simple synchronous access to the `Estimate()` function +NAN_METHOD(CalculateSync) { + NanScope(); + + // expect a number as the first argument + int points = args[0]->Uint32Value(); + double est = Estimate(points); + + NanReturnValue(Number::New(est)); +} +``` + +```c++ +// async.cc +#include +#include "nan.h" +#include "async.h" + +// ... + +using namespace v8; + +class PiWorker : public NanAsyncWorker { + public: + PiWorker(NanCallback *callback, int points) + : NanAsyncWorker(callback), points(points) {} + ~PiWorker() {} + + // Executed inside the worker-thread. + // It is not safe to access V8, or V8 data structures + // here, so everything we need for input and output + // should go on `this`. + void Execute () { + estimate = Estimate(points); + } + + // Executed when the async work is complete + // this function will be run inside the main event loop + // so it is safe to use V8 again + void HandleOKCallback () { + NanScope(); + + Local argv[] = { + Local::New(Null()) + , Number::New(estimate) + }; + + callback->Call(2, argv); + }; + + private: + int points; + double estimate; +}; + +// Asynchronous access to the `Estimate()` function +NAN_METHOD(CalculateAsync) { + NanScope(); + + int points = args[0]->Uint32Value(); + NanCallback *callback = new NanCallback(args[1].As()); + + NanAsyncQueueWorker(new PiWorker(callback, points)); + NanReturnUndefined(); +} +``` + + +## API + + * NAN_METHOD + * NAN_GETTER + * NAN_SETTER + * NAN_PROPERTY_GETTER + * NAN_PROPERTY_SETTER + * NAN_PROPERTY_ENUMERATOR + * NAN_PROPERTY_DELETER + * NAN_PROPERTY_QUERY + * NAN_WEAK_CALLBACK + * NanReturnValue + * NanReturnUndefined + * NanReturnNull + * NanReturnEmptyString + * NanScope + * NanLocker + * NanUnlocker + * NanGetInternalFieldPointer + * NanSetInternalFieldPointer + * NanObjectWrapHandle + * NanMakeWeak + * NanSymbol + * NanGetPointerSafe + * NanSetPointerSafe + * NanFromV8String + * NanBooleanOptionValue + * NanUInt32OptionValue + * NanThrowError, NanThrowTypeError, NanThrowRangeError, NanThrowError(Handle), NanThrowError(Handle, int) + * NanNewBufferHandle(char *, size_t, FreeCallback, void *), NanNewBufferHandle(char *, uint32_t), NanNewBufferHandle(uint32_t) + * NanBufferUse(char *, uint32_t) + * NanNewContextHandle + * NanHasInstance + * NanPersistentToLocal + * NanDispose + * NanAssignPersistent + * NanInitPersistent + * NanCallback + * NanAsyncWorker + * NanAsyncQueueWorker + + +### NAN_METHOD(methodname) + +Use `NAN_METHOD` to define your V8 accessible methods: + +```c++ +// .h: +class Foo : public node::ObjectWrap { + ... + + static NAN_METHOD(Bar); + static NAN_METHOD(Baz); +} + + +// .cc: +NAN_METHOD(Foo::Bar) { + ... +} + +NAN_METHOD(Foo::Baz) { + ... +} +``` + +The reason for this macro is because of the method signature change in 0.11: + +```c++ +// 0.10 and below: +Handle name(const Arguments& args) + +// 0.11 and above +void name(const FunctionCallbackInfo& args) +``` + +The introduction of `FunctionCallbackInfo` brings additional complications: + + +### NAN_GETTER(methodname) + +Use `NAN_GETTER` to declare your V8 accessible getters. You get a `Local` `property` and an appropriately typed `args` object that can act like the `args` argument to a `NAN_METHOD` call. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_GETTER`. + + +### NAN_SETTER(methodname) + +Use `NAN_SETTER` to declare your V8 accessible setters. Same as `NAN_GETTER` but you also get a `Local` `value` object to work with. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_SETTER`. + + +### NAN_PROPERTY_GETTER(cbname) +Use `NAN_PROPERTY_GETTER` to declare your V8 accessible property getters. You get a `Local` `property` and an appropriately typed `args` object that can act similar to the `args` argument to a `NAN_METHOD` call. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_GETTER`. + + +### NAN_PROPERTY_SETTER(cbname) +Use `NAN_PROPERTY_SETTER` to declare your V8 accessible property setters. Same as `NAN_PROPERTY_GETTER` but you also get a `Local` `value` object to work with. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_SETTER`. + + +### NAN_PROPERTY_ENUMERATOR(cbname) +Use `NAN_PROPERTY_ENUMERATOR` to declare your V8 accessible property enumerators. You get an appropriately typed `args` object like the `args` argument to a `NAN_PROPERTY_GETTER` call. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_ENUMERATOR`. + + +### NAN_PROPERTY_DELETER(cbname) +Use `NAN_PROPERTY_DELETER` to declare your V8 accessible property deleters. Same as `NAN_PROPERTY_GETTER`. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_DELETER`. + + +### NAN_PROPERTY_QUERY(cbname) +Use `NAN_PROPERTY_QUERY` to declare your V8 accessible property queries. Same as `NAN_PROPERTY_GETTER`. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_QUERY`. + + +### NAN_WEAK_CALLBACK(type, cbname) + +Use `NAN_WEAK_CALLBACK` to declare your V8 WeakReference callbacks. There is an object argument accessible through `NAN_WEAK_CALLBACK_OBJECT`. The `type` argument gives the type of the `data` argument, accessible through `NAN_WEAK_CALLBACK_DATA(type)`. + +```c++ +static NAN_WEAK_CALLBACK(BufferReference*, WeakCheck) { + if (NAN_WEAK_CALLBACK_DATA(BufferReference*)->noLongerNeeded_) { + delete NAN_WEAK_CALLBACK_DATA(BufferReference*); + } else { + // Still in use, revive, prevent GC + NanMakeWeak(NAN_WEAK_CALLBACK_OBJECT, NAN_WEAK_CALLBACK_DATA(BufferReference*), &WeakCheck); + } +} + +``` + +### NanReturnValue(Handle<Value>) + +Use `NanReturnValue` when you want to return a value from your V8 accessible method: + +```c++ +NAN_METHOD(Foo::Bar) { + ... + + NanReturnValue(String::New("FooBar!")); +} +``` + +No `return` statement required. + + +### NanReturnUndefined() + +Use `NanReturnUndefined` when you don't want to return anything from your V8 accessible method: + +```c++ +NAN_METHOD(Foo::Baz) { + ... + + NanReturnUndefined(); +} +``` + + +### NanReturnNull() + +Use `NanReturnNull` when you want to return `Null` from your V8 accessible method: + +```c++ +NAN_METHOD(Foo::Baz) { + ... + + NanReturnNull(); +} +``` + + +### NanReturnEmptyString() + +Use `NanReturnEmptyString` when you want to return an empty `String` from your V8 accessible method: + +```c++ +NAN_METHOD(Foo::Baz) { + ... + + NanReturnEmptyString(); +} +``` + + +### NanScope() + +The introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanScope()` necessary, use it in place of `HandleScope scope`: + +```c++ +NAN_METHOD(Foo::Bar) { + NanScope(); + + NanReturnValue(String::New("FooBar!")); +} +``` + + +### NanLocker() + +The introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanLocker()` necessary, use it in place of `Locker locker`: + +```c++ +NAN_METHOD(Foo::Bar) { + NanLocker(); + ... + NanUnlocker(); +} +``` + + +### NanUnlocker() + +The introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanUnlocker()` necessary, use it in place of `Unlocker unlocker`: + +```c++ +NAN_METHOD(Foo::Bar) { + NanLocker(); + ... + NanUnlocker(); +} +``` + + +### void * NanGetInternalFieldPointer(Handle<Object>, int) + +Gets a pointer to the internal field with at `index` from a V8 `Object` handle. + +```c++ +Local obj; +... +NanGetInternalFieldPointer(obj, 0); +``` + +### void NanSetInternalFieldPointer(Handle<Object>, int, void *) + +Sets the value of the internal field at `index` on a V8 `Object` handle. + +```c++ +static Persistent dataWrapperCtor; +... +Local wrapper = NanPersistentToLocal(dataWrapperCtor)->NewInstance(); +NanSetInternalFieldPointer(wrapper, 0, this); +``` + + +### Local<Object> NanObjectWrapHandle(Object) + +When you want to fetch the V8 object handle from a native object you've wrapped with Node's `ObjectWrap`, you should use `NanObjectWrapHandle`: + +```c++ +NanObjectWrapHandle(iterator)->Get(String::NewSymbol("end")) +``` + + +### NanMakeWeak(Persistent<T>, parameter, callback) + +Make a persistent reference weak. + + +### String NanSymbol(char *) + +This isn't strictly about compatibility, it's just an easier way to create string symbol objects (i.e. `String::NewSymbol(x)`), for getting and setting object properties, or names of objects. + +```c++ +bool foo = false; +if (obj->Has(NanSymbol("foo"))) + foo = optionsObj->Get(NanSymbol("foo"))->BooleanValue() +``` + + +### Type NanGetPointerSafe(Type *[, Type]) + +A helper for getting values from optional pointers. If the pointer is `NULL`, the function returns the optional default value, which defaults to `0`. Otherwise, the function returns the value the pointer points to. + +```c++ +char *plugh(uint32_t *optional) { + char res[] = "xyzzy"; + uint32_t param = NanGetPointerSafe(optional, 0x1337); + switch (param) { + ... + } + NanSetPointerSafe(optional, 0xDEADBEEF); +} +``` + + +### bool NanSetPointerSafe(Type *, Type) + +A helper for setting optional argument pointers. If the pointer is `NULL`, the function simply return `false`. Otherwise, the value is assigned to the variable the pointer points to. + +```c++ +const char *plugh(size_t *outputsize) { + char res[] = "xyzzy"; + if !(NanSetPointerSafe(outputsize, strlen(res) + 1)) { + ... + } + + ... +} +``` + + +### char* NanFromV8String(Handle<Value>[, enum Nan::Encoding, size_t *, char *, size_t, int]) + +When you want to convert a V8 `String` to a `char*` use `NanFromV8String`. It is possible to define an encoding that defaults to `Nan::UTF8` as well as a pointer to a variable that will be assigned the number of bytes in the returned string. It is also possible to supply a buffer and its length to the function in order not to have a new buffer allocated. The final argument allows optionally setting `String::WriteOptions`, which default to `String::HINT_MANY_WRITES_EXPECTED | String::NO_NULL_TERMINATION`. +Just remember that you'll end up with an object that you'll need to `delete[]` at some point unless you supply your own buffer: + +```c++ +size_t count; +char* name = NanFromV8String(args[0]); +char* decoded = NanFromV8String(args[1], Nan::BASE64, &count, NULL, 0, String::HINT_MANY_WRITES_EXPECTED); +char param_copy[count]; +memcpy(param_copy, decoded, count); +delete[] decoded; +``` + + +### bool NanBooleanOptionValue(Handle<Value>, Handle<String>[, bool]) + +When you have an "options" object that you need to fetch properties from, boolean options can be fetched with this pair. They check first if the object exists (`IsEmpty`), then if the object has the given property (`Has`) then they get and convert/coerce the property to a `bool`. + +The optional last parameter is the *default* value, which is `false` if left off: + +```c++ +// `foo` is false unless the user supplies a truthy value for it +bool foo = NanBooleanOptionValue(optionsObj, NanSymbol("foo")); +// `bar` is true unless the user supplies a falsy value for it +bool bar = NanBooleanOptionValueDefTrue(optionsObj, NanSymbol("bar"), true); +``` + + +### uint32_t NanUInt32OptionValue(Handle<Value>, Handle<String>, uint32_t) + +Similar to `NanBooleanOptionValue`, use `NanUInt32OptionValue` to fetch an integer option from your options object. Can be any kind of JavaScript `Number` and it will be coerced to an unsigned 32-bit integer. + +Requires all 3 arguments as a default is not optional: + +```c++ +uint32_t count = NanUInt32OptionValue(optionsObj, NanSymbol("count"), 1024); +``` + + +### NanThrowError(message), NanThrowTypeError(message), NanThrowRangeError(message), NanThrowError(Local<Value>), NanThrowError(Local<Value>, int) + +For throwing `Error`, `TypeError` and `RangeError` objects. You should `return` this call: + +```c++ +return NanThrowError("you must supply a callback argument"); +``` + +Can also handle any custom object you may want to throw. If used with the error code argument, it will add the supplied error code to the error object as a property called `code`. + + +### Local<Object> NanNewBufferHandle(char *, uint32_t), Local<Object> NanNewBufferHandle(uint32_t) + +The `Buffer` API has changed a little in Node 0.11, this helper provides consistent access to `Buffer` creation: + +```c++ +NanNewBufferHandle((char*)value.data(), value.size()); +``` + +Can also be used to initialize a `Buffer` with just a `size` argument. + +Can also be supplied with a `NAN_WEAK_CALLBACK` and a hint for the garbage collector, when dealing with weak references. + + +### Local<Object> NanBufferUse(char*, uint32_t) + +`Buffer::New(char*, uint32_t)` prior to 0.11 would make a copy of the data. +While it was possible to get around this, it required a shim by passing a +callback. So the new API `Buffer::Use(char*, uint32_t)` was introduced to remove +needing to use this shim. + +`NanBufferUse` uses the `char*` passed as the backing data, and will free the +memory automatically when the weak callback is called. Keep this in mind, as +careless use can lead to "double free or corruption" and other cryptic failures. + + +### bool NanHasInstance(Persistent<FunctionTemplate>&, Handle<Value>) + +Can be used to check the type of an object to determine it is of a particular class you have already defined and have a `Persistent` handle for. + + +### Local<Type> NanPersistentToLocal(Persistent<Type>&) + +Aside from `FunctionCallbackInfo`, the biggest and most painful change to V8 in Node 0.11 is the many restrictions now placed on `Persistent` handles. They are difficult to assign and difficult to fetch the original value out of. + +Use `NanPersistentToLocal` to convert a `Persistent` handle back to a `Local` handle. + +```c++ +Local handle = NanPersistentToLocal(persistentHandle); +``` + + +### Local<Context> NanNewContextHandle([ExtensionConfiguration*, Handle<ObjectTemplate>, Handle<Value>]) +Creates a new `Local` handle. + +```c++ +Local ftmpl = FunctionTemplate::New(); +Local otmpl = ftmpl->InstanceTemplate(); +Local ctx = NanNewContextHandle(NULL, otmpl); +``` + + +### void NanDispose(Persistent<T> &) + +Use `NanDispose` to dispose a `Persistent` handle. + +```c++ +NanDispose(persistentHandle); +``` + + +### NanAssignPersistent(type, handle, object) + +Use `NanAssignPersistent` to assign a non-`Persistent` handle to a `Persistent` one. You can no longer just declare a `Persistent` handle and assign directly to it later, you have to `Reset` it in Node 0.11, so this makes it easier. + +In general it is now better to place anything you want to protect from V8's garbage collector as properties of a generic `Object` and then assign that to a `Persistent`. This works in older versions of Node also if you use `NanAssignPersistent`: + +```c++ +Persistent persistentHandle; + +... + +Local obj = Object::New(); +obj->Set(NanSymbol("key"), keyHandle); // where keyHandle might be a Local +NanAssignPersistent(Object, persistentHandle, obj) +``` + + +### NanInitPersistent(type, name, object) + +User `NanInitPersistent` to declare and initialize a new `Persistent` with the supplied object. The assignment operator for `Persistent` is no longer public in Node 0.11, so this macro makes it easier to declare and initializing a new `Persistent`. See NanAssignPersistent for more information. + +```c++ +Local obj = Object::New(); +obj->Set(NanSymbol("key"), keyHandle); // where keyHandle might be a Local +NanInitPersistent(Object, persistentHandle, obj); +``` + + +### NanCallback + +Because of the difficulties imposed by the changes to `Persistent` handles in V8 in Node 0.11, creating `Persistent` versions of your `Local` handles is annoyingly tricky. `NanCallback` makes it easier by taking your `Local` handle, making it persistent until the `NanCallback` is deleted and even providing a handy `Call()` method to fetch and execute the callback `Function`. + +```c++ +Local callbackHandle = callback = args[0].As(); +NanCallback *callback = new NanCallback(callbackHandle); +// pass `callback` around and it's safe from GC until you: +delete callback; +``` + +You can execute the callback like so: + +```c++ +// no arguments: +callback->Call(0, NULL); + +// an error argument: +Local argv[] = { + Exception::Error(String::New("fail!")) +}; +callback->Call(1, argv); + +// a success argument: +Local argv[] = { + Local::New(Null()), + String::New("w00t!") +}; +callback->Call(2, argv); +``` + +`NanCallback` also has a `Local GetCallback()` method that you can use to fetch a local handle to the underlying callback function if you need it. + + +### NanAsyncWorker + +`NanAsyncWorker` is an abstract class that you can subclass to have much of the annoying async queuing and handling taken care of for you. It can even store arbitrary V8 objects for you and have them persist while the async work is in progress. + +See a rough outline of the implementation: + +```c++ +class NanAsyncWorker { +public: + NanAsyncWorker (NanCallback *callback); + + // Clean up persistent handles and delete the *callback + virtual ~NanAsyncWorker (); + + // Check the `char *errmsg` property and call HandleOKCallback() + // or HandleErrorCallback depending on whether it has been set or not + virtual void WorkComplete (); + + // You must implement this to do some async work. If there is an + // error then allocate `errmsg` to to a message and the callback will + // be passed that string in an Error object + virtual void Execute (); + +protected: + // Set this if there is an error, otherwise it's NULL + const char *errmsg; + + // Save a V8 object in a Persistent handle to protect it from GC + void SavePersistent(const char *key, Local &obj); + + // Fetch a stored V8 object (don't call from within `Execute()`) + Local GetFromPersistent(const char *key); + + // Default implementation calls the callback function with no arguments. + // Override this to return meaningful data + virtual void HandleOKCallback (); + + // Default implementation calls the callback function with an Error object + // wrapping the `errmsg` string + virtual void HandleErrorCallback (); +}; +``` + + +### NanAsyncQueueWorker(NanAsyncWorker *) + +`NanAsyncQueueWorker` will run a `NanAsyncWorker` asynchronously via libuv. Both the *execute* and *after_work* steps are taken care of for you—most of the logic for this is embedded in `NanAsyncWorker`. + +### Contributors + +NAN is only possible due to the excellent work of the following contributors: + +
'; +html += '
Enter Your Password
'; +html += '
'; +html += '
Password:


'; +html += '
'; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "clear_login()") + ' ' + large_icon_button('check', 'Login', 'do_effect_login()') + '
'; +html += '
'; +html += ''; +session.hooks.keys[ENTER_KEY] = 'do_effect_login'; +session.hooks.keys[ESC_KEY] = 'clear_login'; +safe_focus( 'fe_lp_password' ); +show_popup_dialog(450, 225, html); +} +function clear_login() { +hide_popup_dialog(); +Nav.prev(); +} +function do_login() { +if ($('fe_username').value.match(/^\w+$/)) { +session.username = $('fe_username').value; +session.auto_login = $('fe_auto_login').checked; +do_login_prompt_2(); +return; +} +else { +do_openid_login(); +} +} +function do_openid_login() { +if (!$('fe_username').value) return; +session.openid_win = popup_window(''); +if (!session.openid_win) return; +session.open_id = $('fe_username').value; +session.auto_login = $('fe_auto_login') && $('fe_auto_login').checked; +hide_popup_dialog(); +show_progress_dialog(1, "Logging in..."); +session.hooks.before_error = 'close_openid_window'; +session.hooks.after_error = 'do_login_prompt'; +effect_api_send('openid_login', { +OpenID: session.open_id, +Infinite: session.auto_login ? 1 : 0 +}, 'do_openid_login_2'); +} +function close_openid_window() { +if (session.openid_win) { +session.openid_win.close(); +delete session.openid_win; +} +} +function do_openid_login_2(response) { +if (response.CheckURL) { +Debug.trace('openid', "Redirecting popup window to OpenID Check URL: " + response.CheckURL); +show_progress_dialog(1, "Waiting for popup window...", false, ['x', 'Cancel', 'do_login_prompt()']); +session.openid_win.location = response.CheckURL; +session.openid_win.focus(); +} +} +function receive_openid_response(iframe_response) { +var response = deep_copy_object(iframe_response); +Debug.trace('openid', "Received OpenID Response: " + dumper(response)); +hide_popup_dialog(); +if (response.Code) { +close_openid_window(); +return do_error( response.Description ); +} +delete session.hooks.before_error; +delete session.hooks.after_error; +if (response.SessionID) { +session.cookie.set( 'effect_session_id', response.SessionID ); +session.cookie.save(); +} +switch (response.Action) { +case 'popup': +show_progress_dialog(1, "Waiting for popup window...", false, ['x', 'Cancel', 'do_login_prompt()']); +Debug.trace('openid', "Redirecting popup window to OpenID Setup URL: " + response.SetupURL); +session.openid_win.location = response.SetupURL; +session.openid_win.focus(); +break; +case 'login': +close_openid_window(); +do_login_2(response); +break; +case 'register': +if (!response.Info) response.Info = {}; +close_openid_window(); +Debug.trace('openid', 'Original OpenID: ' + response.OpenID_Login); +Debug.trace('openid', 'Clean OpenID: ' + response.OpenID_Unique); +Debug.trace('openid', 'Registration Info: ' + dumper(response.Info)); +session.prereg = response.Info; +session.prereg.open_id_login = response.OpenID_Login; +session.prereg.open_id = response.OpenID_Unique; +if (session.user) { +if (!session.user.OpenIDs) session.user.OpenIDs = {}; +if (!session.user.OpenIDs.OpenID) session.user.OpenIDs.OpenID = []; +var dupe = find_object( session.user.OpenIDs.OpenID, { Unique: session.prereg.open_id } ); +if (dupe) return do_error("That OpenID is already registered and attached to your account. No need to add it again."); +session.user.OpenIDs.OpenID.push({ +Login: session.prereg.open_id_login, +Unique: session.prereg.open_id +}); +setTimeout( function() { +Nav.go('MyAccount', true); +do_message('success', 'Added new OpenID URL to account.'); +}, 1 ); +} +else { +setTimeout( function() { Nav.go('CreateAccount', true); }, 1 ); +} +break; +} +} +function do_effect_login() { +var password = $('fe_lp_password').value; +session.auto_login = $('fe_auto_login').checked; +hide_popup_dialog(); +show_progress_dialog(1, "Logging in..."); +session.hooks.after_error = 'do_login_prompt'; +effect_api_send('user_login', { +Username: session.username, +Password: password, +Infinite: session.auto_login ? 1 : 0 +}, 'do_login_2'); +} +function do_logout() { +effect_api_send('user_logout', {}, 'do_logout_2'); +} +function do_logout_2(response) { +hide_popup_dialog(); +show_default_login_status(); +delete session.hooks.after_error; +delete session.cookie.tree.effect_session_id; +session.cookie.save(); +session.storage = {}; +session.storage_dirty = false; +delete session.user; +delete session.first_login; +var old_username = session.username; +session.username = ''; +if (Nav.inited) { +Nav.go('Main'); +if (old_username) $GR.growl('success', "Logged out of account: " + old_username); +} +else { +Nav.init(); +} +} +function do_login_2(response, tx) { +if (response.FirstLogin) session.first_login = 1; +if (response.User.UserStorage) { +Debug.trace('Recovering site storage blob: session.storage = ' + response.User.UserStorage + ';'); +try { +eval( 'session.storage = ' + response.User.UserStorage + ';' ); +} +catch (e) { +Debug.trace("SITE STORAGE RECOVERY FAILED: " + e); +session.storage = {}; +} +delete response.User.UserStorage; +session.storage_dirty = false; +} +session.user = response.User; +session.username = session.user.Username; +hide_popup_dialog(); +delete session.hooks.after_error; +update_header(); +if (!tx || !tx._from_recover) $GR.growl('success', "Logged in as: " + session.username); +if (session.nav_after_login) { +Nav.go( session.nav_after_login ); +delete session.nav_after_login; +} +else if (Nav.currentAnchor().match(/^Login/)) { +Nav.go('Home'); +} +else { +Nav.refresh(); +} +Nav.init(); +} +function user_storage_mark() { +Debug.trace("Marking user storage as dirty"); +session.storage_dirty = true; +} +function user_storage_idle() { +if (session.storage_dirty && !session.mouseIsDown) { +user_storage_save(); +session.storage_dirty = false; +} +setTimeout( 'user_storage_idle()', 5000 ); +} +function user_storage_save() { +if (session.user) { +Debug.trace("Committing user storage blob"); +effect_api_send('update_user_storage', { Data: serialize(session.storage) }, 'user_storage_save_finish', { _silent: 1 } ); +} +} +function user_storage_save_finish(response, tx) { +} +function show_default_login_status() { +$('d_sidebar_wrapper_recent_games').hide(); +$('d_login_status').innerHTML = '
' + +'
' + +large_icon_button('key', "Login", '#Home') + '' + spacer(1,1) + '' + +'' + large_icon_button('user_add.png', "Signup", '#CreateAccount') + '
' + +'
'; +$('d_tagline').innerHTML = +'Login' + ' | ' + +'Create Account'; +} +function update_header() { +var html = ''; +html += '
'; +html += ''; +html += ''; +html += ''; +html += ''+spacer(2,2)+''; +html += session.user.FullName + '
'; +html += spacer(1,5) + '
'; +html += 'My Home  |  '; +html += 'Logout'; +html += '
'; +$('d_login_status').innerHTML = html; +$('d_tagline').innerHTML = +'Welcome '+session.user.FirstName+'' + ' | ' + +'My Home' + ' | ' + +'Logout'; +effect_api_get( 'get_user_games', { limit:5, offset:0 }, 'receive_sidebar_recent_games', { } ); +} +function receive_sidebar_recent_games(response, tx) { +var html = ''; +if (response.Rows && response.Rows.Row) { +var games = always_array( response.Rows.Row ); +for (var idx = 0, len = games.length; idx < len; idx++) { +var game = games[idx]; +html += ''; +} +html += ''; +$('d_sidebar_recent_games').innerHTML = html; +$('d_sidebar_wrapper_recent_games').show(); +} +else { +$('d_sidebar_wrapper_recent_games').hide(); +} +} +function check_privilege(key) { +if (!session.user) return false; +if (session.user.Privileges.admin == 1) return true; +if (!key.toString().match(/^\//)) key = '/' + key; +var value = lookup_path(key, session.user.Privileges); +return( value && (value != 0) ); +} +function is_admin() { +return check_privilege('admin'); +} +function upgrade_flash_error() { +return alert("Sorry, file upload requires Adobe Flash Player 9 or higher."); +} +function cancel_user_image_manager() { +upload_destroy(); +hide_popup_dialog(); +delete session.hooks.keys[DELETE_KEY]; +} +function do_user_image_manager(callback) { +if (callback) session.uim_callback = callback; +else session.uim_callback = null; +session.temp_last_user_img = null; +session.temp_last_user_image_filename = ''; +var html = '
'; +html += '
Image Manager
'; +html += '
'; +html += ''; +html += '
'; +html += '
'; +html += ''; +html += ''; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', 'cancel_user_image_manager()') + ' ' + large_icon_button('bullet_upload.png', 'Upload Files...', 'upload_basic()', 'b_upload_user_image') + ' ' + large_icon_button('check', 'Choose', 'do_choose_user_image()', 'btn_choose_user_image', '', 'disabled') + '
'; +html += '
'; +session.hooks.keys[ENTER_KEY] = 'do_choose_user_image'; +session.hooks.keys[ESC_KEY] = 'cancel_user_image_manager'; +session.hooks.keys[DELETE_KEY] = 'do_delete_selected_user_image'; +show_popup_dialog(500, 300, html); +var self = this; +setTimeout( function() { +prep_upload('b_upload_user_image', '/effect/api/upload_user_image', [self, 'do_upload_user_image_2'], ['Image Files', '*.jpg;*.jpe;*.jpeg;*.gif;*.png']); +}, 1 ); +var args = { +limit: 50, +offset: 0, +random: Math.random() +}; +effect_api_get( 'user_images_get', args, 'uim_populate_images', { } ); +} +function do_upload_user_image_2() { +effect_api_mod_touch('user_images_get'); +effect_api_send('user_get', { +Username: session.username +}, [this, 'do_upload_user_image_3']); +} +function do_upload_user_image_3(response) { +if (response.User.LastUploadError) return do_error( "Failed to upload image: " + response.User.LastUploadError ); +do_user_image_manager( session.uim_callback ); +} +function uim_populate_images(response, tx) { +var html = ''; +var base_url = '/effect/api/view/users/' + session.username + '/images'; +if (response.Rows && response.Rows.Row) { +var imgs = always_array( response.Rows.Row ); +for (var idx = 0, len = imgs.length; idx < len; idx++) { +var img = imgs[idx]; +var class_name = ((img.Filename == session.temp_last_user_image_filename) ? 'choose_item_selected' : 'choose_item'); +html += ''; +} +} +else { +html = ''; +} +$('d_user_image_list').innerHTML = html; +} +function do_select_user_image(img, filename) { +if (session.temp_last_user_img) session.temp_last_user_img.className = 'choose_item'; +img.className = 'choose_item_selected'; +$('btn_choose_user_image').removeClass('disabled'); +session.temp_last_user_img = img; +session.temp_last_user_image_filename = filename; +} +function do_delete_selected_user_image() { +if (session.temp_last_user_image_filename) { +effect_api_send('user_image_delete', { Filename: session.temp_last_user_image_filename }, 'do_delete_selected_user_image_finish', {}); +} +} +function do_delete_selected_user_image_finish(response, tx) { +try { $('d_user_image_list').removeChild( session.temp_last_user_img ); } catch(e) {;} +session.temp_last_user_img = null; +session.temp_last_user_image_filename = null; +} +function do_choose_user_image() { +if (!session.temp_last_user_image_filename) return; +if (session.uim_callback) { +fire_callback( session.uim_callback, session.temp_last_user_image_filename ); +} +cancel_user_image_manager(); +} +function user_image_thumbnail(filename, width, height, attribs) { +var username = session.username; +if (filename.match(/^(\w+)\/(.+)$/)) { +username = RegExp.$1; +filename = RegExp.$2; +} +var url = '/effect/api/view/users/' + username + '/images/' + filename.replace(/\.(\w+)$/, '_thumb.jpg'); +return ''; +} +function get_user_display(username, full_name, base_url) { +if (!base_url) base_url = ''; +return icon('user', full_name || username, base_url + '#User/' + username); +} +function get_game_tab_bar(game_id, cur_page_name) { +return tab_bar([ +['#Game/' + game_id, 'Game', 'controller.png'], +['#GameDisplay/' + game_id, 'Display', 'monitor.png'], +['#GameAssets/' + game_id, 'Assets', 'folder_page_white.png'], +['#GameObjects/' + game_id, 'Objects', 'bricks.png'], +['#GameAudio/' + game_id, 'Audio', 'sound.gif'], +['#GameKeys/' + game_id, 'Keyboard', 'keyboard.png'], +['#GameLevels/' + game_id, 'Levels', 'world.png'], +['#GamePublisher/' + game_id, 'Publish', 'cd.png'] +], cur_page_name); +} +function get_user_tab_bar(cur_page_name) { +var tabs = [ +['#Home', 'My Home', 'house.png'] +]; +tabs.push( ['#MyAccount', 'Edit Account', 'user_edit.png'] ); +tabs.push( ['#ArticleEdit', 'Post Article', 'page_white_edit.png'] ); +if (config.ProEnabled) { +tabs.push( ['#UserPayments', 'Payments', 'money.png'] ); +} +tabs.push( ['#UserLog', 'Security Log', 'application_view_detail.png'] ); +return tab_bar(tabs, cur_page_name); +} +function get_admin_tab_bar(cur_page_name) { +var tabs = []; +tabs.push( ['#Admin', 'Admin', 'lock.png'] ); +tabs.push( ['#TicketSearch/bugs', 'Bug Tracker', 'bug.png'] ); +tabs.push( ['#TicketSearch/helpdesk', 'Help Desk', 'telephone.png'] ); +tabs.push( ['#AdminReport', 'Reports', 'chart_pie.png'] ); +return tab_bar(tabs, cur_page_name); +} +function get_string(path, args) { +assert(window.config, "get_string() called before config loaded"); +if (!args) args = {}; +args.config = config; +args.session = session; +args.query = session.query; +var value = lookup_path(path, config.Strings); +return (typeof(value) == 'string') ? substitute(value, args) : value; +} +function normalize_dir_path(path) { +if (!path.match(/^\//)) path = '/' + path; +if (!path.match(/\/$/)) path += '/'; +return path; +} +function textedit_window_save(storage_key, filename, content, callback) { +if (!callback) callback = null; +effect_api_mod_touch('textedit'); +if (storage_key.match(/^\/games\/([a-z0-9][a-z0-9\-]*[a-z0-9])\/assets(.+)$/)) { +var game_id = RegExp.$1; +var path = RegExp.$2; +show_progress_dialog(1, "Saving file..."); +effect_api_send('asset_save_file_contents', { +GameID: game_id, +Path: path, +Filename: filename, +Content: content +}, 'textedit_window_save_finish', { _mode: 'asset', _game_id: game_id, _filename: filename, _callback: callback } ); +} +else { +show_progress_dialog(1, "Saving data..."); +effect_api_send('admin_save_file_contents', { +Path: storage_key, +Filename: filename, +Content: content +}, 'textedit_window_save_finish', { _mode: 'admin', _storage_key: storage_key, _filename: filename, _callback: callback } ); +} +} +function textedit_window_save_finish(response, tx) { +hide_progress_dialog(); +if (tx._mode == 'asset') { +do_message('success', "Saved asset: \""+tx._filename+"\""); +show_glog_widget(); +} +else { +do_message('success', "Saved data: \""+tx._storage_key+'/'+tx._filename+"\""); +} +if (tx._callback) tx._callback(); +} +function do_buy(args) { +$P().hide(); +$('d_page_loading').show(); +effect_api_send('create_order', args, 'do_buy_redirect', { _buy_args: args } ); +} +function do_buy_redirect(response, tx) { +var args = tx._buy_args; +$('fe_gco_title').value = args.Title || ''; +$('fe_gco_desc').value = args.Desc || ''; +$('fe_gco_price').value = args.Price || ''; +$('fe_gco_after').value = args.After || ''; +$('fe_gco_unique_id').value = response.OrderID; +Debug.trace('payment', "Redirecting to Google Checkout"); +setTimeout( function() { $('BB_BuyButtonForm').submit(); }, 1 ); +} +function show_glog_widget(game_id) { +if (!game_id) game_id = session.glog_game_id; +if (!game_id) { +$('glog_widget').hide(); +return; +} +if (game_id != session.glog_game_id) { +$('glog_widget').hide(); +session.glog_game_id = game_id; +update_glog_widget(game_id); +} +else { +$('glog_widget').show(); +setTimeout( function() { update_glog_widget(game_id); }, 500 ); +} +} +function update_glog_widget(game_id) { +effect_api_get('game_get_log', { +id: game_id, +offset: 0, +limit: 1, +rand: Math.random() +}, 'receive_glog_data', { _game_id: game_id }); +} +function receive_glog_data(response, tx) { +var game_id = tx._game_id; +if (response && response.Rows && response.Rows.Row) { +var rows = always_array( response.Rows.Row ); +var row = rows[0]; +var html = ''; +html += '
'; +html += '
Latest Game Activity
'; +html += ''; +html += ''; +html += '
'; +html += '
'; +html += ''; +html += ''; +html += ''; +html += '
' + get_buddy_icon_display(row.Username, 1, 0) + ''; +html += '
' + icon( get_icon_for_glog_type(row.Type), ''+row.Message+'' ) + '
'; +html += '
' + get_relative_date(row.Date, true) + '
'; +html += '
'; +$('glog_widget').innerHTML = html; +$('glog_widget').show(); +} +} +function show_glog_post_dialog(game_id) { +hide_popup_dialog(); +delete session.progress; +var html = ''; +html += '
'; +html += '\n \n \n \n'); + }; + __out.push('\n\n'); + __out.push(require('templates/clients/modules/sub_header').call(this, { + heading: t("Ride Request") + })); + __out.push('\n\n\n
\n
\n
\n
\n \n \n \n \n
\n\n
'; +html += '
Post Game Log Message
'; +html += '
'; +html += ''; +html += '
Enter your log message here. Plain text only please.
'; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "hide_popup_dialog()") + ' ' + large_icon_button('check', 'Post Message', "glog_post('"+game_id+"')") + '
'; +html += '
'; +html += ''; +session.hooks.keys[ESC_KEY] = 'hide_popup_dialog'; +safe_focus( 'fe_glog_body' ); +show_popup_dialog(500, 175, html); +} +function glog_post(game_id) { +var msg = trim( $('fe_glog_body').value ); +if (msg) { +hide_popup_dialog(); +effect_api_send('game_post_log', { +GameID: game_id, +Message: msg +}, [this, 'glog_post_finish'], { _game_id: game_id }); +} +} +function glog_post_finish(response, tx) { +show_glog_widget( tx._game_id ); +} +function hide_glog_widget() { +$('glog_widget').hide(); +} +function get_icon_for_glog_type(type) { +var icon = 'page_white.png'; +switch (type) { +case 'asset': icon = 'folder_page_white.png'; break; +case 'game': icon = 'controller.png'; break; +case 'member': icon = 'user'; break; +case 'comment': icon = 'comment.png'; break; +case 'level': icon = 'world.png'; break; +case 'sprite': icon = 'cog.png'; break; +case 'tile': icon = 'brick.png'; break; +case 'tileset': icon = 'color_swatch.png'; break; +case 'rev': icon = 'cd.png'; break; +case 'revision': icon = 'cd.png'; break; +case 'font': icon = 'style.png'; break; +case 'key': icon = 'keyboard.png'; break; +case 'audio': icon = 'sound'; break; +case 'payment': icon = 'money.png'; break; +case 'env': icon = 'weather.png'; break; +case 'environment': icon = 'weather.png'; break; +} +return icon; +} +function effect_load_script(url) { +Debug.trace('api', 'Loading script: ' + url); +load_script(url); +} +function effect_api_get_ie(cmd, params, userData) { +if (!session.api_state_ie) session.api_state_ie = {}; +var unique_id = get_unique_id(); +session.api_state_ie[unique_id] = userData; +params.format = 'js'; +params.onafter = 'effect_api_response_ie(' + unique_id + ', response);'; +var url = '/effect/api/' + cmd + composeQueryString(params); +Debug.trace('api', "Sending MSIE HTTP GET: " + url); +load_script(url); +} +function effect_api_response_ie(unique_id, tree) { +Debug.trace('api', "Got response from MSIE HTTP GET"); +var tx = session.api_state_ie[unique_id]; +delete session.api_state_ie[unique_id]; +if (tree.Code == 'session') { +do_logout_2(); +return; +} +if (tree.Code == 'access') { +do_notice("Access Denied", tree.Description, 'do_not_pass_go'); +return; +} +if (tree.Code != 0) { +if (tx._on_error) return fire_callback( tx._on_error, tree, tx ); +return do_error( tree.Description ); +} +if (tree.SessionID) { +if (tree.SessionID == '_DELETE_') { +delete session.cookie.tree.effect_session_id; +} +else { +session.cookie.set( 'effect_session_id', tree.SessionID ); +} +session.cookie.save(); +} +if (tx._api_callback) { +fire_callback( tx._api_callback, tree, tx ); +} +} +function effect_api_get(cmd, params, callback, userData) { +if (!userData) userData = {}; +userData._api_callback = callback; +if (!session.api_mod_cache[cmd] && session.username) session.api_mod_cache[cmd] = hires_time_now(); +if (!params.mod && session.api_mod_cache[cmd]) params.mod = session.api_mod_cache[cmd]; +if (ie) return effect_api_get_ie(cmd, params, userData); +var url = '/effect/api/' + cmd + composeQueryString(params); +Debug.trace('api', "Sending HTTP GET: " + url); +ajax.get( url, 'effect_api_response', userData ); +} +function effect_api_send(cmd, xml, callback, userData) { +if (!userData) userData = {}; +userData._api_callback = callback; +var data = compose_xml('EffectRequest', xml); +Debug.trace('api', "Sending API Command: " + cmd + ": " + data); +ajax.send({ +method: 'POST', +url: '/effect/api/' + cmd, +data: data, +headers: { 'Content-Type': 'text/xml' } +}, 'effect_api_response', userData); +} +function effect_api_response(tx) { +Debug.trace('api', "HTTP " + tx.response.code + ": " + tx.response.data); +if (tx.response.code == 999) { +if (tx.request._auto_retry) { +session.net_error = false; +show_progress_dialog(1, "Trying to reestablish connection..."); +session.net_error = true; +setTimeout( function() { ajax.send(tx.request); }, 1000 ); +return; +} +else return do_error( "HTTP ERROR: " + tx.response.code + ": " + tx.response.data + ' (URL: ' + tx.request.url + ')' ); +} +if (session.net_error) { +hide_progress_dialog(); +session.net_error = false; +} +if (tx.response.code != 200) { +if (tx._silent) return; +else return do_error( "HTTP ERROR: " + tx.response.code + ": " + tx.response.data + ' (URL: ' + tx.request.url + ')' ); +} +var tree = null; +if (!tx._raw) { +var parser = new XML({ +preserveAttributes: true, +text: tx.response.data +}); +if (parser.getLastError()) return do_error("XML PARSE ERROR: " + parser.getLastError()); +tree = parser.getTree(); +if (tree.Code == 'session') { +do_logout_2(); +return; +} +if (tree.Code == 'access') { +do_notice("Access Denied", tree.Description, 'do_not_pass_go'); +return; +} +if (tree.Code != 0) { +if (tx._on_error) return fire_callback( tx._on_error, tree, tx ); +return do_error( tree.Description ); +} +if (tree.SessionID) { +if (tree.SessionID == '_DELETE_') { +delete session.cookie.tree.effect_session_id; +} +else { +session.cookie.set( 'effect_session_id', tree.SessionID ); +} +session.cookie.save(); +} +} +if (tx._api_callback) { +fire_callback( tx._api_callback, tree, tx ); +} +} +function effect_api_mod_touch() { +for (var idx = 0, len = arguments.length; idx < len; idx++) { +session.api_mod_cache[ arguments[idx] ] = hires_time_now(); +} +} +function do_not_pass_go() { +Nav.go('Main'); +} +var Nav = { +loc: '', +old_loc: '', +inited: false, +nodes: [], +init: function() { +if (!this.inited) { +this.inited = true; +this.loc = 'init'; +this.monitor(); +} +}, +monitor: function() { +var parts = window.location.href.split(/\#/); +var anchor = parts[1]; +if (!anchor) anchor = 'Main'; +var full_anchor = '' + anchor; +var sub_anchor = ''; +anchor = anchor.replace(/\%7C/, '|'); +if (anchor.match(/\|(\w+)$/)) { +sub_anchor = RegExp.$1.toLowerCase(); +anchor = anchor.replace(/\|(\w+)$/, ''); +} +if ((anchor != this.loc) && !anchor.match(/^_/)) { +Debug.trace('nav', "Caught navigation anchor: " + full_anchor); +var page_name = ''; +var page_args = null; +if (full_anchor.match(/^\w+\?.+/)) { +parts = full_anchor.split(/\?/); +page_name = parts[0]; +page_args = parseQueryString( parts[1] ); +} +else if (full_anchor.match(/^(\w+)\/(.*)$/)) { +page_name = RegExp.$1; +page_args = RegExp.$2; +} +else { +parts = full_anchor.split(/\//); +page_name = parts[0]; +page_args = parts.slice(1); +} +Debug.trace('nav', "Calling page: " + page_name + ": " + serialize(page_args)); +hide_popup_dialog(); +var result = page_manager.click( page_name, page_args ); +if (result) { +if (window.pageTracker && (this.loc != 'init')) { +setTimeout( function() { pageTracker._trackPageview('/effect/' + anchor); }, 1000 ); +} +this.old_loc = this.loc; +if (this.old_loc == 'init') this.old_loc = 'Main'; +this.loc = anchor; +} +else { +this.go( this.loc ); +} +} +else if (sub_anchor != this.sub_anchor) { +Debug.trace('nav', "Caught sub-anchor: " + sub_anchor); +$P().gosub( sub_anchor ); +} +this.sub_anchor = sub_anchor; +setTimeout( 'Nav.monitor()', 100 ); +}, +go: function(anchor, force) { +anchor = anchor.replace(/^\#/, ''); +if (force) this.loc = 'init'; +window.location.href = '#' + anchor; +}, +prev: function() { +this.go( this.old_loc || 'Main' ); +}, +refresh: function() { +this.loc = 'refresh'; +}, +bar: function() { +var nodes = arguments; +var html = ''; +for (var idx = 0, len = nodes.length; idx < len; idx++) { +var node = nodes[idx]; +if (node) this.nodes[idx] = node; +else node = this.nodes[idx]; +if (node != '_ignore_') { +html += ''; +} +} +html += '
'; +$('d_nav_bar').innerHTML = html; +}, +title: function(name) { +if (name) document.title = name + ' | EffectGames.com'; +else document.title = 'EffectGames.com'; +}, +currentAnchor: function() { +var parts = window.location.href.split(/\#/); +var anchor = parts[1] || ''; +var sub_anchor = ''; +anchor = anchor.replace(/\%7C/, '|'); +if (anchor.match(/\|(\w+)$/)) { +sub_anchor = RegExp.$1.toLowerCase(); +anchor = anchor.replace(/\|(\w+)$/, ''); +} +return anchor; +} +}; +var Blog = { +edit_caption: '
*Bold*  |Italic|  {monospace}  [http://link]  Formatting Guide...
', +search: function(args) { +if (!args.mode) args.mode = 'and'; +if (!args.offset) args.offset = 0; +if (!args.limit) args.limit = 10; +if (!args.format) args.format = 'xml'; +var query_args = copy_object( args ); +delete query_args.callback; +effect_api_get( 'article_search', query_args, [this, 'search_response'], { _search_args: args } ); +}, +get_article_preview: function(row, args) { +var html = ''; +Debug.trace('blog', 'Row: ' + dumper(row)); +html += '
'; +var ext_article_url = 'http://' + location.hostname + '/effect/article.psp.html' + row.Path + '/' + row.ArticleID; +var article_url = '#Article' + row.Path + '/' + row.ArticleID; +html += ''; +if (!args.title_only) { +html += '
'; +html += row.Preview; +html += '  ' + (args.link_title || 'Read Full Story...') + ''; +html += '
'; +html += ''; +html += '
'; +var elem_class = args.footer_element_class || 'blog_preview_footer_element'; +if ((session.username == row.Username) || is_admin()) { +html += '
' + +icon('page_white_edit.png', "Edit", '#ArticleEdit?path=' + row.Path + '&id=' + row.ArticleID) + '
'; +} +html += '
' + get_user_display(row.Username) + '
'; +html += '
' + icon('calendar', get_short_date_time(row.Published)) + '
'; +html += '
' + icon('talk', row.Comments) + '
'; +if (0 && row.Tags) html += '
' + icon('note.png', make_tag_links(row.Tags, 3)) + '
'; +html += '
' + icon('facebook.png', 'Facebook', "window.open('http://www.facebook.com/sharer.php?u="+encodeURIComponent(ext_article_url)+'&t='+encodeURIComponent(row.Title)+"','sharer','toolbar=0,status=0,width=626,height=436')", "Share on Facebook") + '
'; +html += '
' + icon('twitter.png', 'Twitter', "window.open('http://twitter.com/home?status=Reading%20" + encodeURIComponent(row.Title) + "%3A%20" + encodeURIComponent(ext_article_url)+"')", "Share on Twitter") + '
'; +html += '
'; +html += '
'; +html += '
'; +} +html += '
'; +return html; +}, +search_response: function(response, tx) { +var args = tx._search_args; +if (args.callback) return fire_callback(args.callback, response, args); +var div = $(args.target); +assert(div, "Could not find target DIV: " + args.target); +var html = ''; +if (response.Rows && response.Rows.Row) { +var rows = always_array( response.Rows.Row ); +for (var idx = 0, len = rows.length; idx < len; idx++) { +var row = rows[idx]; +html += this.get_article_preview( row, args ); +} +if (args.more && (rows.length == args.limit)) { +html += large_icon_button('page_white_put.png', 'More...', "Blog.more(this, "+encode_object(args)+")") + '
'; +html += spacer(1,15) + '
'; +} +if (args.after) html += args.after; +} +else if (response.Code != 0) { +html = 'Search Error: ' . response.Code + ': ' + response.Description; +} +else { +html = args.none_found_msg || 'No articles found.'; +} +div.innerHTML = html; +}, +more: function(div, args) { +args.offset += args.limit; +Debug.trace('blog', "More Args: " + dumper(args)); +div.innerHTML = ''; +effect_api_get( 'article_search', args, [this, 'more_response'], { _search_args: args, _div: div } ); +}, +more_response: function(response, tx) { +var args = tx._search_args; +var button = tx._div; +var html = ''; +if (response.Rows && response.Rows.Row) { +var rows = always_array( response.Rows.Row ); +for (var idx = 0, len = rows.length; idx < len; idx++) { +var row = rows[idx]; +html += this.get_article_preview( row, args ); +} +if (args.more && (rows.length == args.limit)) { +html += large_icon_button('page_white_put.png', 'More...', "Blog.more(this, "+encode_object(args)+")") + '
'; +html += spacer(1,15) + '
'; +} +} +else if (response.Code != 0) { +html = 'Search Error: ' . response.Code + ': ' + response.Description; +} +else { +html = args.none_found_msg || 'No more articles found.'; +} +var div = document.createElement('div'); +div.innerHTML = html; +button.parentNode.replaceChild( div, button ); +} +}; +function make_tag_links(csv, max, base_url) { +if (!base_url) base_url = ''; +var tags = csv.split(/\,\s*/); +var append = ''; +if (max && (tags.length > max)) { +tags.length = max; +append = '...'; +} +var html = ''; +for (var idx = 0, len = tags.length; idx < len; idx++) { +html += ''+tags[idx]+''; +if (idx < len - 1) html += ', '; +} +html += append; +return html; +} +function get_url_friendly_title(title) { +title = title.toString().replace(/\W+/g, '_'); +if (title.length > 40) title = title.substring(0, 40); +title = title.replace(/^_+/, ''); +title = title.replace(/_+$/, ''); +return title; +} +function get_full_url(url) { +if (url.match(/^\#/)) { +var parts = window.location.href.split(/\#/); +url = parts[0] + url; +} +return url; +} +var Comments = { +comments_per_page: 10, +get: function(page_id) { +var html = ''; +html += '
'; +html += '
Comments'; +html += '
'; +html += '
'; +html += '
'; +setTimeout( function() { Comments.search({ page_id: page_id }); }, 1 ); +return html; +}, +search: function(args) { +if (!args.limit) args.limit = this.comments_per_page; +if (!args.offset) args.offset = 0; +assert(args.page_id, "Comments.search: No page_id specified"); +args.format = 'xml'; +this.last_search = args; +effect_api_get( 'comments_get', args, [this, 'search_response'], { _search_args: args } ); +}, +research: function(offset) { +var args = this.last_search; +if (!args) return; +args.offset = offset; +effect_api_get( 'comments_get', args, [this, 'search_response'], { _search_args: args } ); +}, +search_response: function(response, tx) { +this.comments = []; +var args = tx._search_args; +if (args.callback) return fire_callback(args.callback, response, args); +var html = ''; +html += '
' + +large_icon_button( 'comment_edit.png', 'Post Comment...', "Comments.add('"+args.page_id+"')" ) + '
'; +if (args.page_id.match(/^Article\//)) { +html += '
' + icon('feed.png', 'RSS', '/effect/api/comment_feed/' + args.page_id + '.rss', 'Comments RSS Feed') + '
'; +} +if (response.Items && response.Items.Item && response.List && response.List.length) { +html += ''; +html += '
'; +var items = this.comments = always_array( response.Items.Item ); +for (var idx = 0, len = items.length; idx < len; idx++) { +var item = items[idx]; +var extra_classes = (args.highlight && (args.highlight == item.ID)) ? ' highlight' : ''; +html += '
'; +html += '
'; +if (item.Username) html += ''; +html += '' + item.Name.toString().toUpperCase() + ''; +if (item.Username) html += ''; +html += ', ' + get_short_date_time(item.Date) + '
'; +html += '
'; +html += this.get_comment_controls( args.page_id, item ); +html += '
'; +html += '
'; +html += '
' + item.Comment + '
'; +html += '
'; +html += ''; +if (item.LastReply && ((item.LastReply >= time_now() - (86400 * 7)) || (session.username && (session.username == item.Username)))) { +setTimeout( "Comments.show_replies('"+args.page_id+"','"+item.ID+"')", 1 ); +} +} +} +else { +} +$( 'd_comments_' + args.page_id ).innerHTML = html; +}, +get_control: function(icon, code, text, status_text) { +if (!icon.match(/\.\w+$/)) icon += '.gif'; +return '' + code_link(code, text, status_text) + ''; +}, +get_comment_controls: function(page_id, comment) { +var html = ''; +var spacer_txt = '  |  '; +if (session.user) { +html += this.get_control('comment', "Comments.reply('"+page_id+"','"+comment.ID+"')", 'Reply') + spacer_txt; +} +if (comment.Replies) { +if (comment._replies_visible) html += this.get_control('magnify_minus', "Comments.hide_replies('"+page_id+"','"+comment.ID+"')", 'Hide Replies'); +else html += this.get_control('magnify_plus', "Comments.show_replies('"+page_id+"','"+comment.ID+"')", 'Show Replies ('+comment.Replies+')'); +if (session.user) html += spacer_txt; +} +if (session.user) { +html += this.get_control( +'star', +"Comments.like('"+page_id+"','"+comment.ID+"')", +'Like' + (comment.Like ? (' ('+comment.Like+')') : ''), +comment.Like ? (comment.Like + ' ' + ((comment.Like == 1) ? 'person likes this' : 'people like this')) : 'I like this comment' +) + spacer_txt; +if (is_admin()) html += this.get_control('trash', "Comments._delete('"+page_id+"','"+comment.ID+"')", 'Delete') + spacer_txt; +html += this.get_control('warning', "Comments.report('"+page_id+"','"+comment.ID+"')", 'Report Abuse'); +} +return html; +}, +reply: function(page_id, comment_id) { +hide_popup_dialog(); +delete session.progress; +var comment = find_object( this.comments, { ID: comment_id } ); +var html = ''; +html += '
'; +html += '\n \n \n \n \n \n \n \n \n \n '); + }, this); + __out.push('\n\n
\n
'; +html += '
Reply to Comment by "'+comment.Name+'"
'; +html += '
'; +var name = this.get_name(); +html += '

Posted by: ' + name; +if (!session.user) html += ' → Create Account'; +html += '


'; +html += ''; +html += Blog.edit_caption; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "hide_popup_dialog()") + ' ' + large_icon_button('check', 'Post Reply', "Comments.post_reply('"+page_id+"','"+comment_id+"')") + '
'; +html += '
'; +html += ''; +session.hooks.keys[ESC_KEY] = 'hide_popup_dialog'; +safe_focus( 'fe_comment_body' ); +show_popup_dialog(600, 300, html); +}, +post_reply: function(page_id, comment_id) { +var value = $('fe_comment_body').value; +if (!value) return; +hide_popup_dialog(); +show_progress_dialog(1, "Posting reply..."); +var name = this.get_name(); +effect_api_mod_touch('comment_replies_get'); +effect_api_send('comment_post_reply', { +PageID: page_id, +CommentID: comment_id, +Username: session.username || '', +Name: name, +Comment: value, +PageURL: location.href +}, [this, 'post_reply_finish'], { _page_id: page_id, _comment_id: comment_id } ); +}, +post_reply_finish: function(response, tx) { +hide_popup_dialog(); +var page_id = tx._page_id; +var comment_id = tx._comment_id; +var comment = find_object( this.comments, { ID: comment_id } ); +do_message('success', "Comment reply posted successfully."); +this.show_replies(page_id, comment_id); +if (!comment.Replies) comment.Replies = 1; else comment.Replies++; +$('d_comment_controls_'+comment_id).innerHTML = this.get_comment_controls( page_id, comment ); +}, +show_replies: function(page_id, comment_id) { +var comment = find_object( this.comments, { ID: comment_id } ); +if (!comment._replies_visible) { +$('d_comment_replies_' + comment_id).show().innerHTML = ''; +} +var args = { page_id: page_id, comment_id: comment_id, offset: 0, limit: 100 }; +effect_api_get( 'comment_replies_get', args, [this, 'receive_replies_response'], { _search_args: args } ); +}, +receive_replies_response: function(response, tx) { +var page_id = tx._search_args.page_id; +var comment_id = tx._search_args.comment_id; +var comment = find_object( this.comments, { ID: comment_id } ); +var html = ''; +var replies = always_array( response.Items.Item ); +for (var idx = 0, len = replies.length; idx < len; idx++) { +var reply = replies[idx]; +html += get_chat_balloon( +(reply.Username == session.username) ? 'blue' : 'grey', +reply.Username, +reply.Comment.replace(/^]*?>(.+)<\/div>$/i, '$1') +); +} +$('d_comment_replies_' + comment_id).innerHTML = html; +if (!comment._replies_visible) { +$('d_comment_replies_' + comment_id).hide(); +animate_div_visibility( 'd_comment_replies_' + comment_id, true ); +} +comment._replies_visible = true; +$('d_comment_controls_'+comment_id).innerHTML = this.get_comment_controls( page_id, comment ); +}, +hide_replies: function(page_id, comment_id) { +var comment = find_object( this.comments, { ID: comment_id } ); +if (comment._replies_visible) { +animate_div_visibility( 'd_comment_replies_' + comment_id, false ); +comment._replies_visible = false; +$('d_comment_controls_'+comment_id).innerHTML = this.get_comment_controls( page_id, comment ); +} +}, +like: function(page_id, comment_id) { +effect_api_mod_touch('comments_get'); +effect_api_send('comment_like', { +PageID: page_id, +CommentID: comment_id +}, [this, 'like_finish'], { _page_id: page_id, _comment_id: comment_id, _on_error: [this, 'like_error'] } ); +}, +like_error: function(response, tx) { +if (response.Code == 'comment_already_like') do_message('error', "You already like this comment."); +else do_error( response.Description ); +}, +like_finish: function(resopnse, tx) { +var page_id = tx._page_id; +var comment_id = tx._comment_id; +var comment = find_object( this.comments, { ID: comment_id } ); +do_message('success', "You now like this comment."); +if (!comment.Like) comment.Like = 1; else comment.Like++; +$('d_comment_controls_'+comment_id).innerHTML = this.get_comment_controls( page_id, comment ); +}, +add: function(page_id) { +hide_popup_dialog(); +delete session.progress; +var html = ''; +html += '
'; +html += '", "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "
'; +html += '
Post New Comment
'; +html += '
'; +var name = this.get_name(); +html += '

Posted by: ' + name; +if (!session.user) html += ' → Create Account'; +html += '


'; +html += ''; +html += Blog.edit_caption; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "hide_popup_dialog()") + ' ' + large_icon_button('check', 'Post Comment', "Comments.post('"+page_id+"')") + '
'; +html += '
'; +html += ''; +session.hooks.keys[ESC_KEY] = 'hide_popup_dialog'; +safe_focus( 'fe_comment_body' ); +show_popup_dialog(600, 300, html); +}, +report: function(page_id, comment_id) { +if (confirm('Are you sure you want to report this comment to the site administrators as abusive and/or spam?')) { +effect_api_send('comment_report_abuse', { +PageID: page_id, +CommentID: comment_id +}, [this, 'report_finish'], { _page_id: page_id, _comment_id: comment_id } ); +} +}, +report_finish: function(response, tx) { +do_message('success', 'Your abuse report has been received, and will be evaluated by the site administrators.'); +}, +_delete: function(page_id, comment_id) { +if (confirm('Are you sure you want to permanently delete this comment?')) { +effect_api_mod_touch('comments_get'); +effect_api_send('comment_delete', { +PageID: page_id, +CommentID: comment_id +}, [this, 'delete_finish'], { _page_id: page_id, _comment_id: comment_id } ); +} +}, +delete_finish: function(response, tx) { +do_message('success', 'The comment was deleted successfully.'); +var page_id = tx._page_id; +this.search({ page_id: page_id }); +}, +get_name: function() { +var name = '(Anonymous)'; +if (session.user) { +if (get_bool_pref('public_profile')) name = session.user.FullName; +else name = session.username; +} +return name; +}, +post: function(page_id) { +var value = $('fe_comment_body').value; +if (!value) return; +hide_popup_dialog(); +show_progress_dialog(1, "Posting comment..."); +var name = this.get_name(); +effect_api_mod_touch('comments_get'); +effect_api_send('comment_post', { +PageID: page_id, +Username: session.username || '', +Name: name, +Comment: value +}, [this, 'post_finish'], { _page_id: page_id } ); +}, +post_finish: function(response, tx) { +hide_popup_dialog(); +var comment_id = response.CommentID; +var page_id = tx._page_id; +this.search({ page_id: page_id, highlight: comment_id }); +} +}; +Class.create( 'Menu', { +id: '', +menu: null, +__construct: function(id) { +this.id = id; +}, +load: function() { +if (!this.menu) { +this.menu = $(this.id); +assert( !!this.menu, "Could not locate DOM element: " + this.id ); +} +}, +get_value: function() { +this.load(); +return this.menu.options[this.menu.selectedIndex].value; +}, +set_value: function(value, auto_add) { +value = str_value(value); +this.load(); +for (var idx = 0, len = this.menu.options.length; idx < len; idx++) { +if (this.menu.options[idx].value == value) { +this.menu.selectedIndex = idx; +return true; +} +} +if (auto_add) { +this.menu.options[this.menu.options.length] = new Option(value, value); +this.menu.selectedIndex = this.menu.options.length - 1; +return true; +} +return false; +}, +disable: function() { +this.load(); +this.menu.disabled = true; +this.menu.setAttribute( 'disabled', 'disabled' ); +}, +enable: function() { +this.load(); +this.menu.setAttribute( 'disabled', '' ); +this.menu.disabled = false; +}, +populate: function(items, sel_value) { +this.load(); +this.menu.options.length = 0; +for (var idx = 0, len = items.length; idx < len; idx++) { +var item = items[idx]; +var item_name = ''; +var item_value = ''; +if (isa_hash(item)) { +item_name = item.label; +item_value = item.data; +} +else if (isa_array(item)) { +item_name = item[0]; +item_value = item[1]; +} +else { +item_name = item_value = item; +} +this.menu.options[ this.menu.options.length ] = new Option( item_name, item_value ); +if (item_value == sel_value) this.menu.selectedIndex = idx; +} +} +} ); +Class.subclass( Menu, 'MultiMenu', { +__static: { +toggle_type: function(id) { +var menu = $(id); +assert(menu, "Could not find menu in DOM: " + id); +if (menu.disabled) return; +var obj = MenuManager.find(id); +assert(obj, "Could not find menu in MenuManager: " + id); +var div = $( 'd_inner_' + id ); +var ic = $( 'ic_' + id ); +var is_multiple = (ic.src.indexOf('contract') > -1); +obj.multi = !is_multiple; +var multiple_tag = !is_multiple ? +' multiple="multiple" size=5' : ''; +var items = []; +for (var idx = 0; idx < menu.options.length; idx++) { +var option = menu.options[idx]; +array_push( items, { +value: option.value, +text: option.text, +selected: option.selected +}); +} +var html = ''; +html += ''; +div.innerHTML = html; +ic.src = images_uri + '/menu_' + (is_multiple ? 'expand' : 'contract') + '.gif'; +obj.menu = null; +} +}, +attribs: null, +multi: false, +toggle: true, +__construct: function(id, attribs) { +this.id = id; +if (attribs) this.attribs = attribs; +}, +get_html: function(items, selected_csv, attribs) { +if (!items) items = []; +if (!selected_csv) selected_csv = ''; +if (attribs) this.attribs = attribs; +var selected = csv_to_hash(selected_csv); +this.menu = null; +if (num_keys(selected) > 1) this.multi = true; +var html = '
'; +html += ''; +html += ''; +html += ''; +if (this.toggle) html += ''; +html += '
' + spacer(1,1) + '
'+spacer(1,2)+'
'; +html += '
'; +return html; +}, +get_value: function() { +this.load(); +var value = ''; +for (var idx = 0; idx < this.menu.options.length; idx++) { +var option = this.menu.options[idx]; +if (option.selected && option.value.length) { +if (value.length > 0) value += ','; +value += option.value; +} +} +return value; +}, +set_value: function(value, auto_add) { +value = '' + value; +this.load(); +if (!value) { +value = ''; +for (var idx = 0; idx < this.menu.options.length; idx++) { +var option = this.menu.options[idx]; +option.selected = (option.value == value); +} +return; +} +var selected = csv_to_hash(value); +if ((num_keys(selected) > 1) && !this.multi) { +MultiMenu.toggle_type(this.id); +var self = this; +setTimeout( function() { +self.set_value(value, auto_add); +}, 1 ); +return; +} +for (var idx = 0; idx < this.menu.options.length; idx++) { +var option = this.menu.options[idx]; +option.selected = selected[option.value] ? true : false; +} +}, +populate: function(items, value) { +this.load(); +this.menu.options.length = 0; +if (!value) value = ''; +var selected = csv_to_hash(value); +for (var idx = 0, len = items.length; idx < len; idx++) { +var item = items[idx]; +var item_name = ''; +var item_value = ''; +if (isa_hash(item)) { +item_name = item.label; +item_value = item.data; +} +else if (isa_array(item)) { +item_name = item[0]; +item_value = item[1]; +} +else { +item_name = item_value = item; +} +var opt = new Option( item_name, item_value ); +this.menu.options[ this.menu.options.length ] = opt; +opt.selected = selected[item_value] ? true : false; +} +}, +collapse: function() { +if (this.multi) MultiMenu.toggle_type(this.id); +}, +expand: function() { +if (!this.multi) MultiMenu.toggle_type(this.id); +} +} ); +Class.create( 'MenuManager', { +__static: { +menus: {}, +register: function(menu) { +this.menus[ menu.id ] = menu; +return menu; +}, +find: function(id) { +return this.menus[id]; +} +} +} ); +Class.create( 'GrowlManager', { +lifetime: 10, +marginRight: 0, +marginTop: 0, +__construct: function() { +this.growls = []; +}, +growl: function(type, msg) { +if (find_object(this.growls, { type: type, msg: msg })) return; +var div = $(document.createElement('div')); +div.className = 'growl_message ' + type; +div.setOpacity(0.0); +div.innerHTML = '
' + msg + '
' + spacer(1,5) + '
'; +$('d_growl_wrapper').insertBefore( div, $('d_growl_top').nextSibling ); +var growl = { id:get_unique_id(), type: type, msg: msg, opacity:0.0, start:hires_time_now(), div:div }; +this.growls.push(growl); +this.handle_resize(); +this.animate(growl); +var self = this; +div.onclick = function() { +delete_object(self.growls, { id: growl.id }); +$('d_growl_wrapper').removeChild( div ); +}; +}, +animate: function(growl) { +if (growl.deleted) return; +var now = hires_time_now(); +var div = growl.div; +if (now - growl.start <= 0.5) { +div.setOpacity( tweenFrame(0.0, 1.0, (now - growl.start) * 2, 'EaseOut', 'Quadratic') ); +} +else if (now - growl.start <= this.lifetime) { +if (!growl._fully_opaque) { +div.setOpacity( 1.0 ); +growl._fully_opaque = true; +} +} +else if (now - growl.start <= this.lifetime + 1.0) { +div.setOpacity( tweenFrame(1.0, 0.0, (now - growl.start) - this.lifetime, 'EaseOut', 'Quadratic') ); +} +else { +delete_object(this.growls, { id: growl.id }); +$('d_growl_wrapper').removeChild( div ); +return; +} +var self = this; +setTimeout( function() { self.animate(growl); }, 33 ); +}, +handle_resize: function() { +var div = $('d_growl_wrapper'); +if (this.growls.length) { +var size = getInnerWindowSize(); +div.style.top = '' + (10 + this.marginTop) + 'px'; +div.style.left = '' + Math.floor((size.width - 310) - this.marginRight) + 'px'; +} +else { +div.style.left = '-2000px'; +} +} +} ); +window.$GR = new GrowlManager(); +if (window.addEventListener) { +window.addEventListener( "resize", function() { +$GR.handle_resize(); +}, false ); +} +else if (window.attachEvent && !ie6) { +window.attachEvent("onresize", function() { +$GR.handle_resize(); +}); +} +Class.create( 'Effect.Page', { +ID: '', +data: null, +active: false, +__construct: function(config) { +if (!config) return; +this.data = {}; +if (!config) config = {}; +for (var key in config) this[key] = config[key]; +this.div = $('page_' + this.ID); +assert(this.div, "Cannot find page div: page_" + this.ID); +}, +onInit: function() { +}, +onActivate: function() { +return true; +}, +onDeactivate: function() { +return true; +}, +show: function() { +this.div.show(); +}, +hide: function() { +this.div.hide(); +}, +gosub: function(anchor) { +} +} ); +Class.require( 'Effect.Page' ); +Class.create( 'Effect.PageManager', { +pages: null, +current_page_id: '', +on_demand: {}, +__construct: function(page_list) { +this.pages = []; +this.page_list = page_list; +for (var idx = 0, len = page_list.length; idx < len; idx++) { +Debug.trace( 'page', "Initializing page: " + page_list[idx].ID ); +if (Effect.Page[ page_list[idx].ID ]) { +var page = new Effect.Page[ page_list[idx].ID ]( page_list[idx] ); +page.onInit(); +this.pages.push(page); +} +else { +Debug.trace( 'page', 'Page ' + page_list[idx].ID + ' will be loaded on-demand' ); +} +} +}, +find: function(id) { +var page = find_object( this.pages, { ID: id } ); +if (!page) Debug.trace('PageManager', "Could not find page: " + id); +return page; +}, +notify_load: function(file, id) { +for (var idx = 0, len = this.page_list.length; idx < len; idx++) { +var page_config = this.page_list[idx]; +if (page_config.File == file) { +Debug.trace( 'page', "Initializing page on-demand: " + page_config.ID ); +var page = new Effect.Page[ page_config.ID ]( page_config ); +page.onInit(); +this.pages.push(page); +} +} +var self = this; +setTimeout( function() { +var result = self.activate(id, self.temp_args); +delete self.temp_args; +$('d_page_loading').hide(); +if (!result) { +$('page_'+id).hide(); +self.current_page_id = ''; +} +}, 1 ); +}, +activate: function(id, args) { +if (!find_object( this.pages, { ID: id } )) { +var page_config = find_object( this.page_list, { ID: id } ); +assert(!!page_config, "Page config not found: " + id ); +Debug.trace('page', "Loading file on-demand: " + page_config.File + " for page: " + id); +var url = '/effect/api/load_page/' + page_config.File + '?onafter=' + escape('page_manager.notify_load(\''+page_config.File+'\',\''+id+'\')'); +if (page_config.Requires) { +var files = page_config.Requires.split(/\,\s*/); +for (var idx = 0, len = files.length; idx < len; idx++) { +var filename = files[idx]; +if (!this.on_demand[filename]) { +Debug.trace('page', "Also loading file: " + filename); +url += '&file=' + filename; +this.on_demand[filename] = 1; +} +} +} +$('d_page_loading').show(); +this.temp_args = args; +load_script( url ); +return true; +} +$('page_'+id).show(); +var page = this.find(id); +page.active = true; +if (!args) args = []; +if (!isa_array(args)) args = [ args ]; +var result = page.onActivate.apply(page, args); +if (typeof(result) == 'boolean') return result; +else return alert("Page " + id + " onActivate did not return a boolean!"); +}, +deactivate: function(id, new_id) { +var page = this.find(id); +var result = page.onDeactivate(new_id); +if (result) { +$('page_'+id).hide(); +page.active = false; +} +return result; +}, +click: function(id, args) { +Debug.trace('page', "Switching pages to: " + id); +var old_id = this.current_page_id; +if (this.current_page_id) { +var result = this.deactivate( this.current_page_id, id ); +if (!result) return false; +} +this.current_page_id = id; +this.old_page_id = old_id; +window.scrollTo( 0, 0 ); +var result = this.activate(id, args); +if (!result) { +$('page_'+id).hide(); +this.current_page_id = ''; +} +return true; +} +} ); +Class.subclass( Effect.Page, "Effect.Page.Main", { +inited: false, +onActivate: function() { +Nav.bar( ['Main', 'EffectGames.com'] ); +Nav.title(''); +$('d_blog_news').innerHTML = loading_image(); +$('d_blog_community').innerHTML = loading_image(); +$('d_blog_featured').innerHTML = loading_image(); +Blog.search({ +stag: 'featured_game', +limit: 4, +full: 1, +callback: [this, 'receive_featured_games'] +}); +effect_api_get( 'get_site_info', { cat: 'pop_pub_games' }, [this, 'receive_pop_pub_games'], { } ); +Blog.search({ +stag: 'front_page', +limit: 5, +target: 'd_blog_news', +more: 1 +}); +Blog.search({ +path: '/community', +limit: 5, +target: 'd_blog_community', +more: 1 +}); +if (!this.inited) { +this.inited = true; +config.Strings.MainSlideshow.Slide = always_array( config.Strings.MainSlideshow.Slide ); +this.slide_idx = 0; +this.num_slides = config.Strings.MainSlideshow.Slide.length; +this.slide_div_num = 0; +this.slide_dir = 1; +this.bk_pos = -340; +this.bk_pos_target = -340; +this.slide_images = []; +for (var idx = 0, len = this.num_slides; idx < len; idx++) { +var url = images_uri + '/' + config.Strings.MainSlideshow.Slide[idx].Photo; +this.slide_images[idx] = new Image(); +this.slide_images[idx].src = png(url, true); +} +} +this.height_target = 470; +this.height_start = $('d_header').offsetHeight; +this.time_start = hires_time_now(); +this.duration = 0.75; +if (!this.timer) this.timer = setTimeout( '$P("Main").animate_mhs()', 33 ); +if (session.user) $('d_blurb_main').hide(); +else { +$('d_blurb_main').innerHTML = get_string('/Main/Blurb'); +$('d_blurb_main').show(); +} +return true; +}, +receive_pop_pub_games: function(response, tx) { +var html = ''; +if (response.Data && response.Data.Games && response.Data.Games.Game) { +var games = always_array( response.Data.Games.Game ); +for (var idx = 0, len = Math.min(games.length, 16); idx < len; idx++) { +var game = games[idx]; +html += '
' + +(game.Logo ? +user_image_thumbnail(game.Logo, 80, 60) : +'' +) + '
' + ww_fit_box(game.Title, 80, 2, session.em_width, 1) + '
'; +} +html += '
'; +} +else { +html += 'No active public games found! Why not create a new one?'; +} +$('d_main_pop_pub_games').innerHTML = html; +}, +receive_featured_games: function(response, tx) { +var html = ''; +if (response.Rows && response.Rows.Row) { +html += ''; +var rows = always_array( response.Rows.Row ); +for (var idx = 0, len = rows.length; idx < len; idx++) { +var row = rows[idx]; +var image_url = row.Params.featured_image; +if (image_url && image_url.match(/^(\w+)\/(\w+\.\w+)$/)) { +image_url = '/effect/api/view/users/' + RegExp.$1 + '/images/' + RegExp.$2; +} +if (idx % 2 == 0) html += ''; +html += ''; +if (idx % 2 == 1) html += ''; +} +if (rows.length % 2 == 1) { +html += ''; +html += ''; +} +html += '
'; +html += ''; +html += ''; +html += ''; +html += ''; +html += ''; +html += '
'; +html += ''; +html += '' + spacer(10,1) + ''; +html += ''; +html += ''; +html += '' + spacer(15,1) + '
'; +html += spacer(1,20); +html += '
'; +} +$('d_blog_featured').innerHTML = html; +}, +animate_mhs: function() { +var now = hires_time_now(); +if (now - this.time_start >= this.duration) { +$('d_header').style.height = '' + this.height_target + 'px'; +$('d_shadow').style.height = '' + this.height_target + 'px'; +delete this.timer; +} +else { +var height = tweenFrame(this.height_start, this.height_target, (now - this.time_start) / this.duration, 'EaseOut', 'Circular'); +$('d_header').style.height = '' + height + 'px'; +$('d_shadow').style.height = '' + height + 'px'; +this.timer = setTimeout( '$P("Main").animate_mhs()', 33 ); +} +}, +onDeactivate: function() { +$('d_blog_news').innerHTML = ''; +$('d_blog_community').innerHTML = ''; +this.height_target = 75; +this.height_start = $('d_header').offsetHeight; +this.time_start = hires_time_now(); +if (!this.timer) this.timer = setTimeout( '$P("Main").animate_mhs()', 33 ); +return true; +}, +draw_slide: function() { +if (this.slide_timer) return; +var slide = config.Strings.MainSlideshow.Slide[ this.slide_idx ]; +this.old_photo = $('d_header_slideshow_photo_' + this.slide_div_num); +this.old_text = $('d_header_slideshow_text_' + this.slide_div_num); +this.slide_div_num = 1 - this.slide_div_num; +this.new_photo = $('d_header_slideshow_photo_' + this.slide_div_num); +this.new_text = $('d_header_slideshow_text_' + this.slide_div_num); +this.new_photo.style.backgroundImage = 'url('+png(images_uri+'/'+slide.Photo, true)+')'; +this.new_photo.setOpacity(0.0); +var html = ''; +html += slide.Text; +this.slide_width = this.new_text.offsetWidth; +this.new_text.innerHTML = html; +if (this.slide_dir == 1) this.new_text.style.left = '' + this.slide_width + 'px'; +else this.new_text.style.left = '-' + this.slide_width + 'px'; +this.slide_time_start = hires_time_now(); +this.slide_timer = setTimeout( '$P("Main").animate_mhs_slide()', 33 ); +}, +animate_mhs_slide: function() { +var now = hires_time_now(); +if (now - this.slide_time_start >= this.duration) { +this.new_text.style.left = '0px'; +this.old_text.style.left = '-' + this.slide_width + 'px'; +this.new_photo.setOpacity( 1.0 ); +this.old_photo.setOpacity( 0.0 ); +delete this.slide_timer; +this.bk_pos = this.bk_pos_target; +} +else { +var value = tweenFrame(0.0, 1.0, (now - this.slide_time_start) / this.duration, 'EaseOut', 'Circular'); +if (this.slide_dir == 1) { +this.new_text.style.left = '' + Math.floor( this.slide_width - (this.slide_width * value) ) + 'px'; +this.old_text.style.left = '-' + Math.floor( this.slide_width * value ) + 'px'; +} +else { +this.new_text.style.left = '-' + Math.floor( this.slide_width - (this.slide_width * value) ) + 'px'; +this.old_text.style.left = '' + Math.floor( this.slide_width * value ) + 'px'; +} +this.new_photo.setOpacity( value ); +this.old_photo.setOpacity( 1.0 - value ); +var bkp = Math.floor( this.bk_pos + ((this.bk_pos_target - this.bk_pos) * value) ); +$('d_header').style.backgroundPosition = '' + bkp + 'px 0px'; +this.slide_timer = setTimeout( '$P("Main").animate_mhs_slide()', 33 ); +} +}, +prev_slide: function() { +this.bk_pos_target += 200; +this.slide_idx--; +if (this.slide_idx < 0) this.slide_idx += this.num_slides; +this.slide_dir = -1; +this.draw_slide(); +}, +next_slide: function() { +this.bk_pos_target -= 200; +this.slide_idx++; +if (this.slide_idx >= this.num_slides) this.slide_idx -= this.num_slides; +this.slide_dir = 1; +this.draw_slide(); +} +} ); +Class.subclass( Effect.Page, "Effect.Page.PublicGameList", { +onActivate: function() { +Nav.bar( +['Main', 'EffectGames.com'], +['PublicGameList', "All Public Games"] +); +Nav.title( "List of All Public Game Projects" ); +effect_api_get( 'get_site_info', { cat: 'all_pub_games' }, [this, 'receive_all_pub_games'], { } ); +this.div.innerHTML = loading_image(); +return true; +}, +onDeactivate: function() { +this.div.innerHTML = ''; +return true; +}, +receive_all_pub_games: function(response, tx) { +var html = ''; +html += '

List of All Public Game Projects

'; +html += '
This is the complete list of public games currently being built by our users, presented in alphabetical order. Maybe they could use some help! Check out the game project pages and see (requires user account).
'; +if (response.Data && response.Data.Games && response.Data.Games.Game) { +var games = always_array( response.Data.Games.Game ); +for (var idx = 0, len = games.length; idx < len; idx++) { +var game = games[idx]; +html += '
' + +(game.Logo ? +user_image_thumbnail(game.Logo, 80, 60) : +'' +) + '
' + ww_fit_box(game.Title, 80, 2, session.em_width, 1) + '
'; +} +html += '
'; +} +else { +html += 'No public games found! Why not create a new one?'; +} +this.div.innerHTML = html; +} +} ); +Class.subclass( Effect.Page, "Effect.Page.Search", { +onActivate: function(args) { +if (!args) args = {}; +var search_text = args.q; +var start = args.s || 0; +if (!start) start = 0; +var title = 'Search results for "'+search_text+'"'; +Nav.bar( +['Main', 'EffectGames.com'], +['Search?q=' + escape(search_text), "Search Results"] +); +Nav.title( title ); +this.last_search_text = search_text; +$('d_article_search').innerHTML = loading_image(); +load_script( 'http://www.google.com/uds/GwebSearch?callback=receive_google_search_results&context=0&lstkp=0&rsz=large&hl=en&source=gsc&gss=.com&sig=&q='+escape(search_text)+'%20site%3Ahttp%3A%2F%2Fwww.effectgames.com%2F&key=notsupplied&v=1.0&start='+start+'&nocache=' + (new Date()).getTime() ); +$('h_article_search').innerHTML = title; +return true; +}, +onDeactivate: function(new_page) { +$('fe_search_bar').value = ''; +$('d_article_search').innerHTML = ''; +return true; +} +} ); +function do_search_bar() { +var search_text = $('fe_search_bar').value; +if (search_text.length) { +Nav.go('Search?q=' + escape(search_text)); +} +} +function receive_google_search_results(context, response) { +var html = ''; +html += '
Powered by
'; +if (response.results.length) { +for (var idx = 0, len = response.results.length; idx < len; idx++) { +var row = response.results[idx]; +var url = row.unescapedUrl.replace(/^.+article\.psp\.html/, '#Article'); +html += '
'; +html += ''; +html += '
' + row.content + '
'; +html += '
'; +} +} +else { +html += 'No results found.'; +} +if (response.cursor.pages) { +html += '
Page: '; +for (var idx = 0, len = response.cursor.pages.length; idx < len; idx++) { +html += ''; +var page = response.cursor.pages[idx]; +var url = '#Search?q=' + escape($P('Search').last_search_text) + '&s=' + page.start; +if (response.cursor.currentPageIndex != idx) html += ''; +else html += ''; +html += page.label; +if (response.cursor.currentPageIndex != idx) html += ''; +else html += ''; +html += ''; +} +html += '
'; +} +$('d_article_search').innerHTML = html; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/index.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/index.js new file mode 100644 index 00000000..8b164a42 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/index.js @@ -0,0 +1 @@ +exports.ZeParser = require('./ZeParser').ZeParser; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/package.json new file mode 100644 index 00000000..90320447 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/package.json @@ -0,0 +1,27 @@ +{ + "author": { + "name": "Peter van der Zee", + "url": "http://qfox.nl/" + }, + "name": "zeparser", + "description": "My JavaScript parser", + "version": "0.0.5", + "homepage": "https://github.com/qfox/ZeParser/", + "repository": { + "type": "git", + "url": "git://github.com/qfox/ZeParser.git" + }, + "main": "./index", + "engines": { + "node": "*" + }, + "dependencies": {}, + "devDependencies": {}, + "readme": "This is a JavaScript parser.\nhttp://github.com/qfox/ZeParser\n(c) Peter van der Zee\nhttp://qfox.nl\n\n\nBenchmark\nhttp://qfox.github.com/ZeParser/benchmark.html\n\nThe Tokenizer is used by the parser. The parser tells the tokenizer whether the next token may be a regular expression or not. Without the parser, the tokenizer will fail if regular expression literals are used in the input.\n\nUsage:\nZeParser.parse(input);\n\nReturns a \"parse tree\" which is a tree of an array of arrays with tokens (regular objects) as leafs. Meta information embedded as properties (of the arrays and the tokens).\n\nZeParser.createParser(input);\n\nReturns a new ZeParser instance which has already parsed the input. Amongst others, the ZeParser instance will have the properties .tree, .wtree and .btree.\n\n.tree is the parse tree mentioned above.\n.wtree (\"white\" tree) is a regular array with all the tokens encountered (including whitespace, line terminators and comments)\n.btree (\"black\" tree) is just like .wtree but without the whitespace, line terminators and comments. This is what the specification would call the \"token stream\".\n\nI'm aware that the naming convention is a bit awkward. It's a tradeoff between short and descriptive. The streams are used quite often in the analysis.\n\nTokens are regular objects with several properties. Amongst them are .tokposw and .tokposw, they correspond with their own position in the .wtree and .btree.\n\nThe parser has two modes for parsing: simple and extended. Simple mode is mainly for just parsing and returning the streams and a simple parse tree. There's not so much meta information here and this mode is mainly built for speed. The other mode has everything required for Zeon to do its job. This mode is toggled by the instance property .ast, which is true by default :)\n\nNon-factory example:\n\nvar input = \"foo\";\nvar tree = []; // this should probably be refactored away some day\nvar tokenizer = new Tokenizer(input); // dito\nvar parser = new ZeParser(input, tokenizer, tree);\nparser.parse(); // returns tree..., should never throw errors\n", + "readmeFilename": "README", + "bugs": { + "url": "https://github.com/qfox/ZeParser/issues" + }, + "_id": "zeparser@0.0.5", + "_from": "zeparser@0.0.5" +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-parser.html b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-parser.html new file mode 100755 index 00000000..1ff5ff43 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-parser.html @@ -0,0 +1,26 @@ + + + + Parser Test Suite Page + + + + (c) qfox.nl
+ Parser test suite
+
Running...
+ + + + + + + \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-tokenizer.html b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-tokenizer.html new file mode 100755 index 00000000..0e0d1b1a --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-tokenizer.html @@ -0,0 +1,23 @@ + + + + Tokenizer Test Suite Page + + + + (c) qfox.nl
+ + + + + + \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/tests.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/tests.js new file mode 100644 index 00000000..8a4138be --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/tests.js @@ -0,0 +1,478 @@ +// tests for both the tokenizer and parser. Parser test results could be checked tighter. +// api: [input, token-output-count, ?regex-hints, desc] +// regex-hints are for tokenizer, will tell for each token whether it might parse regex or not (parser's job) +var Tests = [ + +["var abc;", 4, "Variable Declaration"], +["var abc = 5;", 8, "Variable Declaration, Assignment"], +["/* */", 1, "Block Comment"], +["/** **/", 1, "JSDoc-style Comment"], +["var f = function(){;};", 13, "Assignment, Function Expression"], +["hi; // moo", 4, "Trailing Line Comment"], +["hi; // moo\n;", 6, "Trailing Line Comment, Linefeed, `;`"], +["var varwithfunction;", 4, "Variable Declaration, Identifier Containing Reserved Words, `;`"], +["a + b;", 6, "Addition/Concatenation"], + +["'a'", 1, "Single-Quoted String"], +["'a';", 2, "Single-Quoted String, `;`"], // Taken from the parser test suite. + +["'a\\n'", 1, "Single-Quoted String With Escaped Linefeed"], +["'a\\n';", 2, "Single-Quoted String With Escaped Linefeed, `;`"], // Taken from the parser test suite. + +["\"a\"", 1, "Double-Quoted String"], +["\"a\";", 2, "Double-Quoted String, `;`"], // Taken from the parser test suite. + +["\"a\\n\"", 1, "Double-Quoted String With Escaped Linefeed"], +["\"a\\n\";", 2, "Double-Quoted String With Escaped Linefeed, `;`"], // Taken from the parser test suite. + +["500", 1, "Integer"], +["500;", 2, "Integer, `;`"], // Taken from the parser test suite. + +["500.", 1, "Double With Trailing Decimal Point"], +["500.;", 2, "Double With Trailing Decimal Point"], // Taken from the parser test suite. + +["500.432", 1, "Double With Decimal Component"], +["500.432;", 2, "Double With Decimal Component, `;`"], // Taken from the parser test suite. + +[".432432", 1, "Number, 0 < Double < 1"], +[".432432;", 2, "Number, 0 < Double < 1, `;`"], // Taken from the parser test suite. + +["(a,b,c)", 7, "Parentheses, Comma-separated identifiers"], +["(a,b,c);", 8, "Parentheses, Comma-separated identifiers, `;`"], // Taken from the parser test suite. + +["[1,2,abc]", 7, "Array literal"], +["[1,2,abc];", 8, "Array literal, `;`"], // Taken from the parser test suite. + +["{a:1,\"b\":2,c:c}", 13, "Object literal"], +["var o = {a:1,\"b\":2,c:c};", 20, "Assignment, Object Literal, `;`"], // Taken from the parser test suite. + +["var x;\nvar y;", 9, "2 Variable Declarations, Multiple lines"], +["var x;\nfunction n(){ }", 13, "Variable, Linefeed, Function Declaration"], +["var x;\nfunction n(abc){ }", 14, "Variable, Linefeed, Function Declaration With One Argument"], +["var x;\nfunction n(abc, def){ }", 17, "Variable, Linefeed, Function Declaration With Multiple Arguments"], +["function n(){ \"hello\"; }", 11, "Function Declaration, Body"], + +["/a/;", 2, [true, false], "RegExp Literal, `;`"], +["/a/b;", 2, [true, true], "RegExp Literal, Flags, `;`"], +["++x;", 3, "Unary Increment, Prefix, `;`"], +[" / /;", 3, [true, true, false], "RegExp, Leading Whitespace, `;`"], +["/ / / / /", 5, [true, false, false, false, true], "RegExp Containing One Space, Space, Division, Space, RegExp Containing One Space"], + +// Taken from the parser test suite. + +["\"var\";", 2, "Keyword String, `;`"], +["\"variable\";", 2, "String Beginning With Keyword, `;`"], +["\"somevariable\";", 2, "String Containing Keyword, `;`"], +["\"somevar\";", 2, "String Ending With Keyword, `;`"], + +["var varwithfunction;", 4, "Keywords should not be matched in identifiers"], + +["var o = {a:1};", 12, "Object Literal With Unquoted Property"], +["var o = {\"b\":2};", 12, "Object Literal With Quoted Property"], +["var o = {c:c};", 12, "Object Literal With Equivalent Property Name and Identifier"], + +["/a/ / /b/;", 6, [true, true, false, false, true, false], "RegExp, Division, RegExp, `;`"], +["a/b/c;", 6, "Triple Division (Identifier / Identifier / Identifier)"], + +["+function(){/regex/;};", 9, [false, false, false, false, false, true, false, false, false], "Unary `+` Operator, Function Expression Containing RegExp and Semicolon, `;`"], + +// Line Terminators. +["\r\n", 1, "CRLF Line Ending = 1 Linefeed"], +["\r", 1, "CR Line Ending = 1 Linefeed"], +["\n", 1, "LF Line Ending = 1 Linefeed"], +["\r\n\n\u2028\u2029\r", 5, "Various Line Terminators"], + +// Whitespace. +["a \t\u000b\u000c\u00a0\uFFFFb", 8, "Whitespace"], + +// Comments. +["//foo!@#^&$1234\nbar;", 4, "Line Comment, Linefeed, Identifier, `;`"], +["/* abcd!@#@$* { } && null*/;", 2, "Single-Line Block Comment, `;`"], +["/*foo\nbar*/;", 2, "Multi-Line Block Comment, `;`"], +["/*x*x*/;", 2, "Block Comment With Asterisks, `;`"], +["/**/;", 2, "Empty Comment, `;`"], + +// Identifiers. +["x;", 2, "Single-Character Identifier, `;`"], +["_x;", 2, "Identifier With Leading `_`, `;`"], +["xyz;", 2, "Identifier With Letters Only, `;`"], +["$x;", 2, "Identifier With Leading `$`, `;`"], +["x5;", 2, "Identifier With Number As Second Character, `;`"], +["x_y;", 2, "Identifier Containing `_`, `;`"], +["x+5;", 4, "Identifier, Binary `+` Operator, Identifier, `;`"], +["xyz123;", 2, "Alphanumeric Identifier, `;`"], +["x1y1z1;", 2, "Alternating Alphanumeric Identifier, `;`"], +["foo\\u00d8bar;", 2, "Identifier With Unicode Escape Sequence (`\\uXXXX`), `;`"], +["f\u00d8\u00d8bar;", 2, "Identifier With Embedded Unicode Character"], + +// Numbers. +["5;", 2, "Integer, `;`"], +["5.5;", 2, "Double, `;`"], +["0;", 2, "Integer Zero, `;`"], +["0.0;", 2, "Double Zero, `;`"], +["0.001;", 2, "0 < Decimalized Double < 1, `;`"], +["1.e2;", 2, "Integer With Decimal and Exponential Component (`e`), `;`"], +["1.e-2;", 2, "Integer With Decimal and Negative Exponential Component, `;`"], +["1.E2;", 2, "Integer With Decimal and Uppercase Exponential Component (`E`), `;`"], +["1.E-2;", 2, "Integer With Decimal and Uppercase Negative Exponential Component, `;`"], +[".5;", 2, "0 < Double < 1, `;`"], +[".5e3;", 2, "(0 < Double < 1) With Exponential Component"], +[".5e-3;", 2, "(0 < Double < 1) With Negative Exponential Component"], +["0.5e3;", 2, "(0 < Decimalized Double < 1) With Exponential Component"], +["55;", 2, "Two-Digit Integer, `;`"], +["123;", 2, "Three-Digit Integer, `;`"], +["55.55;", 2, "Two-Digit Double, `;`"], +["55.55e10;", 2, "Two-Digit Double With Exponential Component, `;`"], +["123.456;", 2, "Three-Digit Double, `;`"], +["1+e;", 4, "Additive Expression, `;`"], +["0x01;", 2, "Hexadecimal `1` With 1 Leading Zero, `;`"], +["0xcafe;", 2, "Hexadecimal `51966`, `;`"], +["0x12345678;", 2, "Hexadecimal `305419896`, `;`"], +["0x1234ABCD;", 2, "Hexadecimal `305441741` With Uppercase Letters, `;`"], +["0x0001;", 2, "Hexadecimal `1` with 3 Leading Zeros, `;`"], + +// Strings. +["\"foo\";", 2, "Multi-Character Double-Quoted String, `;`"], +["\"a\\n\";", 2, "Double-Quoted String Containing Linefeed, `;`"], +["\'foo\';", 2, "Single-Quoted String, `;`"], +["'a\\n';", 2, "Single-Quoted String Containing Linefeed, `;`"], +["\"x\";", 2, "Single-Character Double-Quoted String, `;`"], +["'';", 2, "Empty Single-Quoted String, `;`"], +["\"foo\\tbar\";", 2, "Double-Quoted String With Tab Character, `;`"], +["\"!@#$%^&*()_+{}[]\";", 2, "Double-Quoted String Containing Punctuators, `;`"], +["\"/*test*/\";", 2, "Double-Quoted String Containing Block Comment, `;`"], +["\"//test\";", 2, "Double-Quoted String Containing Line Comment, `;`"], +["\"\\\\\";", 2, "Double-Quoted String Containing Reverse Solidus, `;`"], +["\"\\u0001\";", 2, "Double-Quoted String Containing Numeric Unicode Escape Sequence, `;`"], +["\"\\uFEFF\";", 2, "Double-Quoted String Containing Alphanumeric Unicode Escape Sequence, `;`"], +["\"\\u10002\";", 2, "Double-Quoted String Containing 5-Digit Unicode Escape Sequence, `;`"], +["\"\\x55\";", 2, "Double-Quoted String Containing Hex Escape Sequence, `;`"], +["\"\\x55a\";", 2, "Double-Quoted String Containing Hex Escape Sequence and Additional Character, `;`"], +["\"a\\\\nb\";", 2, "Double-Quoted String Containing Escaped Linefeed, `;`"], +["\";\"", 1, "Double-Quoted String Containing `;`"], +["\"a\\\nb\";", 2, "Double-Quoted String Containing Reverse Solidus and Linefeed, `;`"], +["'\\\\'+ ''", 4, "Single-Quoted String Containing Reverse Solidus, `+`, Empty Single-Quoted String"], + +// `null`, `true`, and `false`. +["null;", 2, "`null`, `;`"], +["true;", 2, "`true`, `;`"], +["false;", 2, "`false`, `;`"], + +// RegExps +["/a/;", 2, [true, true], "Single-Character RegExp, `;`"], +["/abc/;", 2, [true, true], "Multi-Character RegExp, `;`"], +["/abc[a-z]*def/g;", 2, [true, true], "RegExp Containing Character Range and Quantifier, `;`"], +["/\\b/;", 2, [true, true], "RegExp Containing Control Character, `;`"], +["/[a-zA-Z]/;", 2, [true, true], "RegExp Containing Extended Character Range, `;`"], +["/foo(.*)/g;", 2, [true, false], "RegExp Containing Capturing Group and Quantifier, `;`"], + +// Array Literals. +["[];", 3, "Empty Array, `;`"], +["[\b\n\f\r\t\x20];", 9, "Array Containing Whitespace, `;`"], +["[1];", 4, "Array Containing 1 Element, `;`"], +["[1,2];", 6, "Array Containing 2 Elements, `;`"], +["[1,2,,];", 8, "Array Containing 2 Elisions, `;`"], +["[1,2,3];", 8, "Array Containing 3 Elements, `;`"], +["[1,2,3,,,];", 11, "Array Containing 3 Elisions, `;`"], + +// Object Literals. +["({x:5});", 8, "Object Literal Containing 1 Member; `;`"], +["({x:5,y:6});", 12, "Object Literal Containing 2 Members, `;`"], +["({x:5,});", 9, "Object Literal Containing 1 Member and Trailing Comma, `;`"], +["({if:5});", 8, "Object Literal Containing Reserved Word Property Name, `;`"], +["({ get x() {42;} });", 17, "Object Literal Containing Getter, `;`"], +["({ set y(a) {1;} });", 18, "Object Literal Containing Setter, `;`"], + +// Member Expressions. +["o.m;", 4, "Dot Member Accessor, `;`"], +["o['m'];", 5, "Square Bracket Member Accessor, `;`"], +["o['n']['m'];", 8, "Nested Square Bracket Member Accessor, `;`"], +["o.n.m;", 6, "Nested Dot Member Accessor, `;`"], +["o.if;", 4, "Dot Reserved Property Name Accessor, `;`"], + +// Function Calls. +["f();", 4, "Function Call Operator, `;`"], +["f(x);", 5, "Function Call Operator With 1 Argument, `;`"], +["f(x,y);", 7, "Function Call Operator With Multiple Arguments, `;`"], +["o.m();", 6, "Dot Member Accessor, Function Call, `;`"], +["o['m']();", 7, "Square Bracket Member Accessor, Function Call, `;`"], +["o.m(x);", 7, "Dot Member Accessor, Function Call With 1 Argument, `;`"], +["o['m'](x);", 8, "Square Bracket Member Accessor, Function Call With 1 Argument, `;`"], +["o.m(x,y);", 9, "Dot Member Accessor, Function Call With 2 Arguments, `;`"], +["o['m'](x,y);", 10, "Square Bracket Member Accessor, Function Call With 2 Arguments, `;`"], +["f(x)(y);", 8, "Nested Function Call With 1 Argument Each, `;`"], +["f().x;", 6, "Function Call, Dot Member Accessor, `;`"], + +// `eval` Function. +["eval('x');", 5, "`eval` Invocation With 1 Argument, `;`"], +["(eval)('x');", 7, "Direct `eval` Call Example, `;`"], +["(1,eval)('x');", 9, "Indirect `eval` Call Example, `;`"], +["eval(x,y);", 7, "`eval` Invocation With 2 Arguments, `;`"], + +// `new` Operator. +["new f();", 6, "`new` Operator, Function Call, `;`"], +["new o;", 4, "`new` Operator, Identifier, `;`"], +["new o.m;", 6, "`new` Operator, Dot Member Accessor, `;`"], +["new o.m(x);", 9, "`new` Operator, Dot Member Accessor, Function Call With 1 Argument, `;`"], +["new o.m(x,y);", 11, "``new` Operator, Dot Member Accessor, Function Call With 2 Arguments , `;`"], + +// Prefix and Postfix Increment. +["++x;", 3, "Prefix Increment, Identifier, `;`"], +["x++;", 3, "Identifier, Postfix Increment, `;`"], +["--x;", 3, "Prefix Decrement, Identifier, `;`"], +["x--;", 3, "Postfix Decrement, Identifier, `;`"], +["x ++;", 4, "Identifier, Space, Postfix Increment, `;`"], +["x /* comment */ ++;", 6, "Identifier, Block Comment, Postfix Increment, `;`"], +["++ /* comment */ x;", 6, "Prefix Increment, Block Comment, Identifier, `;`"], + +// Unary Operators. +["delete x;", 4, "`delete` Operator, Space, Identifier, `;`"], +["void x;", 4, "`void` Operator, Space, Identifier, `;`"], +["typeof x;", 4, "`typeof` Operator, Space, Identifier, `;`"], +["+x;", 3, "Unary `+` Operator, Identifier, `;`"], +["-x;", 3, "Unary Negation Operator, Identifier, `;`"], +["~x;", 3, "Bitwise NOT Operator, Identifier, `;`"], +["!x;", 3, "Logical NOT Operator, Identifier, `;`"], + +// Comma Operator. +["x, y;", 5, "Comma Operator"], + +// Miscellaneous. +["new Date++;", 5, "`new` Operator, Identifier, Postfix Increment, `;`"], +["+x++;", 4, "Unary `+`, Identifier, Postfix Increment, `;`"], + +// Expressions. +["1 * 2;", 6, "Integer, Multiplication, Integer, `;`"], +["1 / 2;", 6, "Integer, Division, Integer, `;`"], +["1 % 2;", 6, "Integer, Modulus, Integer, `;`"], +["1 + 2;", 6, "Integer, Addition, Integer, `;`"], +["1 - 2;", 6, "Integer, Subtraction, Integer, `;`"], +["1 << 2;", 6, "Integer, Bitwise Left Shift, Integer, `;`"], +["1 >>> 2;", 6, "Integer, Bitwise Zero-fill Right Shift, Integer, `;`"], +["1 >> 2;", 6, "Integer, Bitwise Sign-Propagating Right Shift, Integer, `;`"], +["1 * 2 + 3;", 10, "Order-of-Operations Expression, `;`"], +["(1+2)*3;", 8, "Parenthesized Additive Expression, Multiplication, `;`"], +["1*(2+3);", 8, "Multiplication, Parenthesized Additive Expression, `;`"], +["xy;", 4, "Greater-Than Relational Operator, `;`"], +["x<=y;", 4, "Less-Than-or-Equal-To Relational Operator, `;`"], +["x>=y;", 4, "Greater-Than-or-Equal-To Relational Operator, `;`"], +["x instanceof y;", 6, "`instanceof` Operator, `;`"], +["x in y;", 6, "`in` Operator, `;`"], +["x&y;", 4, "Bitwise AND Operator, `;`"], +["x^y;", 4, "Bitwise XOR Operator, `;`"], +["x|y;", 4, "Bitwise OR Operator, `;`"], +["x+y>>= y;", 6, "Bitwise Zero-Fill Right Shift Assignment, `;`"], +["x <<= y;", 6, "Bitwise Left Shift Assignment, `;`"], +["x += y;", 6, "Additive Assignment, `;`"], +["x -= y;", 6, "Subtractive Assignment, `;`"], +["x *= y;", 6, "Multiplicative Assignment, `;`"], +["x /= y;", 6, "Divisive Assignment, `;`"], +["x %= y;", 6, "Modulus Assignment, `;`"], +["x >>= y;", 6, "Bitwise Sign-Propagating Right Shift Assignment, `;`"], +["x &= y;", 6, "Bitwise AND Assignment, `;`"], +["x ^= y;", 6, "Bitwise XOR Assignment, `;`"], +["x |= y;", 6, "Bitwise OR Assignment, `;`"], + +// Blocks. +["{};", 3, "Empty Block, `;`"], +["{x;};", 5, "Block Containing 1 Identifier, `;`"], +["{x;y;};", 7, "Block Containing 2 Identifiers, `;`"], + +// Variable Declarations. +["var abc;", 4, "Variable Declaration"], +["var x,y;", 6, "Comma-Separated Variable Declarations, `;`"], +["var x=1,y=2;", 10, "Comma-Separated Variable Initializations, `;`"], +["var x,y=2;", 8, "Variable Declaration, Variable Initialization, `;`"], + +// Empty Statements. +[";", 1, "Empty Statement"], +["\n;", 2, "Linefeed, `;`"], + +// Expression Statements. +["x;", 2, "Identifier, `;`"], +["5;", 2, "Integer, `;`"], +["1+2;", 4, "Additive Statement, `;`"], + +// `if...else` Statements. +["if (c) x; else y;", 13, "Space-Delimited `if...else` Statement"], +["if (c) x;", 8, "Space-Delimited `if` Statement, `;`"], +["if (c) {} else {};", 14, "Empty Block-Delimited `if...else` Statement"], +["if (c1) if (c2) s1; else s2;", 19, "Nested `if...else` Statement Without Dangling `else`"], + +// `while` and `do...while` Loops. +["do s; while (e);", 11, "Space-Delimited `do...while` Loop"], +["do { s; } while (e);", 15, "Block-Delimited `do...while` Loop"], +["while (e) s;", 8, "Space-Delimited `while` Loop"], +["while (e) { s; };", 13, "Block-Delimited `while` Loop"], + +// `for` and `for...in` Loops. +["for (;;) ;", 8, "Infinite Space-Delimited `for` Loop"], +["for (;c;x++) x;", 12, "`for` Loop: Empty Initialization Condition; Space-Delimited Body"], +["for (i;i foo(new window[(['Active'].concat('Object').join('X'))])\n```\n\n## License\n\nLicensed under the MIT license.\n\n[socket.io]: http://socket.io/\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/felixge/node-active-x-obfuscator/issues" + }, + "_id": "active-x-obfuscator@0.0.1", + "_from": "active-x-obfuscator@0.0.1" +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/test.js new file mode 100644 index 00000000..e8fc807f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/test.js @@ -0,0 +1,53 @@ +var activeXObfuscator = require('./index'); +var assert = require('assert'); + +var OBFUSCATED_ACTIVE_X_OBJECT = activeXObfuscator.OBFUSCATED_ACTIVE_X_OBJECT; +var OBFUSCATED_ACTIVE_X = activeXObfuscator.OBFUSCATED_ACTIVE_X; + +var input = + "foo(new ActiveXObject('Microsoft.XMLHTTP'))"; +var expected = + "foo(new window[" + OBFUSCATED_ACTIVE_X_OBJECT + "]('Microsoft.XMLHTTP'))"; +assert.equal(activeXObfuscator(input), expected); + +var input = + "var foo = 'ActiveXObject';"; +var expected = + "var foo = " + OBFUSCATED_ACTIVE_X_OBJECT + ";"; +assert.equal(activeXObfuscator(input), expected); + +var input = + 'var foo = "ActiveXObject";'; +var expected = + "var foo = " + OBFUSCATED_ACTIVE_X_OBJECT + ";"; +assert.equal(activeXObfuscator(input), expected); + +var input = + 'var foo = o.ActiveXObject;'; +var expected = + "var foo = o[" + OBFUSCATED_ACTIVE_X_OBJECT + "];"; +assert.equal(activeXObfuscator(input), expected); + +var input = + 'var foo = "ActiveX";'; +var expected = + "var foo = " + OBFUSCATED_ACTIVE_X + ";"; +assert.equal(activeXObfuscator(input), expected); + +var input = + "var foo = 'ActiveX';"; +var expected = + "var foo = " + OBFUSCATED_ACTIVE_X + ";"; +assert.equal(activeXObfuscator(input), expected); + +var input = + "var foo; // ActiveX is cool"; +var expected = + "var foo; // Ac...eX is cool"; +assert.equal(activeXObfuscator(input), expected); + +var input = + "var foo = 'ActiveX is cool';"; +assert.throws(function() { + activeXObfuscator(input); +}, /Unknown ActiveX occurence/); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/.npmignore b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/.npmignore new file mode 100644 index 00000000..d97eaa09 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/.npmignore @@ -0,0 +1,4 @@ +.DS_Store +.tmp*~ +*.local.* +.pinf-* \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.html b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.html new file mode 100644 index 00000000..5f37ac0f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.html @@ -0,0 +1,981 @@ + + + + +UglifyJS – a JavaScript parser/compressor/beautifier + + + + + + + + + + + + + +
+ +
+ +
+

UglifyJS – a JavaScript parser/compressor/beautifier

+ + + + +
+

1 UglifyJS — a JavaScript parser/compressor/beautifier

+
+ + +

+This package implements a general-purpose JavaScript +parser/compressor/beautifier toolkit. It is developed on NodeJS, but it +should work on any JavaScript platform supporting the CommonJS module system +(and if your platform of choice doesn't support CommonJS, you can easily +implement it, or discard the exports.* lines from UglifyJS sources). +

+

+The tokenizer/parser generates an abstract syntax tree from JS code. You +can then traverse the AST to learn more about the code, or do various +manipulations on it. This part is implemented in parse-js.js and it's a +port to JavaScript of the excellent parse-js Common Lisp library from Marijn Haverbeke. +

+

+( See cl-uglify-js if you're looking for the Common Lisp version of +UglifyJS. ) +

+

+The second part of this package, implemented in process.js, inspects and +manipulates the AST generated by the parser to provide the following: +

+
    +
  • ability to re-generate JavaScript code from the AST. Optionally + indented—you can use this if you want to “beautify” a program that has + been compressed, so that you can inspect the source. But you can also run + our code generator to print out an AST without any whitespace, so you + achieve compression as well. + +
  • +
  • shorten variable names (usually to single characters). Our mangler will + analyze the code and generate proper variable names, depending on scope + and usage, and is smart enough to deal with globals defined elsewhere, or + with eval() calls or with{} statements. In short, if eval() or + with{} are used in some scope, then all variables in that scope and any + variables in the parent scopes will remain unmangled, and any references + to such variables remain unmangled as well. + +
  • +
  • various small optimizations that may lead to faster code but certainly + lead to smaller code. Where possible, we do the following: + +
      +
    • foo["bar"] ==> foo.bar + +
    • +
    • remove block brackets {} + +
    • +
    • join consecutive var declarations: + var a = 10; var b = 20; ==> var a=10,b=20; + +
    • +
    • resolve simple constant expressions: 1 +2 * 3 ==> 7. We only do the + replacement if the result occupies less bytes; for example 1/3 would + translate to 0.333333333333, so in this case we don't replace it. + +
    • +
    • consecutive statements in blocks are merged into a sequence; in many + cases, this leaves blocks with a single statement, so then we can remove + the block brackets. + +
    • +
    • various optimizations for IF statements: + +
        +
      • if (foo) bar(); else baz(); ==> foo?bar():baz(); +
      • +
      • if (!foo) bar(); else baz(); ==> foo?baz():bar(); +
      • +
      • if (foo) bar(); ==> foo&&bar(); +
      • +
      • if (!foo) bar(); ==> foo||bar(); +
      • +
      • if (foo) return bar(); else return baz(); ==> return foo?bar():baz(); +
      • +
      • if (foo) return bar(); else something(); ==> {if(foo)return bar();something()} + +
      • +
      + +
    • +
    • remove some unreachable code and warn about it (code that follows a + return, throw, break or continue statement, except + function/variable declarations). + +
    • +
    • act a limited version of a pre-processor (c.f. the pre-processor of + C/C++) to allow you to safely replace selected global symbols with + specified values. When combined with the optimisations above this can + make UglifyJS operate slightly more like a compilation process, in + that when certain symbols are replaced by constant values, entire code + blocks may be optimised away as unreachable. +
    • +
    + +
  • +
+ + + +
+ +
+

1.1 Unsafe transformations

+
+ + +

+The following transformations can in theory break code, although they're +probably safe in most practical cases. To enable them you need to pass the +--unsafe flag. +

+ +
+ +
+

1.1.1 Calls involving the global Array constructor

+
+ + +

+The following transformations occur: +

+ + + +
new Array(1, 2, 3, 4)  => [1,2,3,4]
+Array(a, b, c)         => [a,b,c]
+new Array(5)           => Array(5)
+new Array(a)           => Array(a)
+
+ + +

+These are all safe if the Array name isn't redefined. JavaScript does allow +one to globally redefine Array (and pretty much everything, in fact) but I +personally don't see why would anyone do that. +

+

+UglifyJS does handle the case where Array is redefined locally, or even +globally but with a function or var declaration. Therefore, in the +following cases UglifyJS doesn't touch calls or instantiations of Array: +

+ + + +
// case 1.  globally declared variable
+  var Array;
+  new Array(1, 2, 3);
+  Array(a, b);
+
+  // or (can be declared later)
+  new Array(1, 2, 3);
+  var Array;
+
+  // or (can be a function)
+  new Array(1, 2, 3);
+  function Array() { ... }
+
+// case 2.  declared in a function
+  (function(){
+    a = new Array(1, 2, 3);
+    b = Array(5, 6);
+    var Array;
+  })();
+
+  // or
+  (function(Array){
+    return Array(5, 6, 7);
+  })();
+
+  // or
+  (function(){
+    return new Array(1, 2, 3, 4);
+    function Array() { ... }
+  })();
+
+  // etc.
+
+ + +
+ +
+ +
+

1.1.2 obj.toString() ==> obj+“”

+
+ + +
+
+ +
+ +
+

1.2 Install (NPM)

+
+ + +

+UglifyJS is now available through NPM — npm install uglify-js should do +the job. +

+
+ +
+ +
+

1.3 Install latest code from GitHub

+
+ + + + + +
## clone the repository
+mkdir -p /where/you/wanna/put/it
+cd /where/you/wanna/put/it
+git clone git://github.com/mishoo/UglifyJS.git
+
+## make the module available to Node
+mkdir -p ~/.node_libraries/
+cd ~/.node_libraries/
+ln -s /where/you/wanna/put/it/UglifyJS/uglify-js.js
+
+## and if you want the CLI script too:
+mkdir -p ~/bin
+cd ~/bin
+ln -s /where/you/wanna/put/it/UglifyJS/bin/uglifyjs
+  # (then add ~/bin to your $PATH if it's not there already)
+
+ + +
+ +
+ +
+

1.4 Usage

+
+ + +

+There is a command-line tool that exposes the functionality of this library +for your shell-scripting needs: +

+ + + +
uglifyjs [ options... ] [ filename ]
+
+ + +

+filename should be the last argument and should name the file from which +to read the JavaScript code. If you don't specify it, it will read code +from STDIN. +

+

+Supported options: +

+
    +
  • -b or --beautify — output indented code; when passed, additional + options control the beautifier: + +
      +
    • -i N or --indent N — indentation level (number of spaces) + +
    • +
    • -q or --quote-keys — quote keys in literal objects (by default, + only keys that cannot be identifier names will be quotes). + +
    • +
    + +
  • +
  • --ascii — pass this argument to encode non-ASCII characters as + \uXXXX sequences. By default UglifyJS won't bother to do it and will + output Unicode characters instead. (the output is always encoded in UTF8, + but if you pass this option you'll only get ASCII). + +
  • +
  • -nm or --no-mangle — don't mangle names. + +
  • +
  • -nmf or --no-mangle-functions – in case you want to mangle variable + names, but not touch function names. + +
  • +
  • -ns or --no-squeeze — don't call ast_squeeze() (which does various + optimizations that result in smaller, less readable code). + +
  • +
  • -mt or --mangle-toplevel — mangle names in the toplevel scope too + (by default we don't do this). + +
  • +
  • --no-seqs — when ast_squeeze() is called (thus, unless you pass + --no-squeeze) it will reduce consecutive statements in blocks into a + sequence. For example, "a = 10; b = 20; foo();" will be written as + "a=10,b=20,foo();". In various occasions, this allows us to discard the + block brackets (since the block becomes a single statement). This is ON + by default because it seems safe and saves a few hundred bytes on some + libs that I tested it on, but pass --no-seqs to disable it. + +
  • +
  • --no-dead-code — by default, UglifyJS will remove code that is + obviously unreachable (code that follows a return, throw, break or + continue statement and is not a function/variable declaration). Pass + this option to disable this optimization. + +
  • +
  • -nc or --no-copyright — by default, uglifyjs will keep the initial + comment tokens in the generated code (assumed to be copyright information + etc.). If you pass this it will discard it. + +
  • +
  • -o filename or --output filename — put the result in filename. If + this isn't given, the result goes to standard output (or see next one). + +
  • +
  • --overwrite — if the code is read from a file (not from STDIN) and you + pass --overwrite then the output will be written in the same file. + +
  • +
  • --ast — pass this if you want to get the Abstract Syntax Tree instead + of JavaScript as output. Useful for debugging or learning more about the + internals. + +
  • +
  • -v or --verbose — output some notes on STDERR (for now just how long + each operation takes). + +
  • +
  • -d SYMBOL[=VALUE] or --define SYMBOL[=VALUE] — will replace + all instances of the specified symbol where used as an identifier + (except where symbol has properly declared by a var declaration or + use as function parameter or similar) with the specified value. This + argument may be specified multiple times to define multiple + symbols - if no value is specified the symbol will be replaced with + the value true, or you can specify a numeric value (such as + 1024), a quoted string value (such as ="object"= or + ='https://github.com'), or the name of another symbol or keyword (such as =null or document). + This allows you, for example, to assign meaningful names to key + constant values but discard the symbolic names in the uglified + version for brevity/efficiency, or when used wth care, allows + UglifyJS to operate as a form of conditional compilation + whereby defining appropriate values may, by dint of the constant + folding and dead code removal features above, remove entire + superfluous code blocks (e.g. completely remove instrumentation or + trace code for production use). + Where string values are being defined, the handling of quotes are + likely to be subject to the specifics of your command shell + environment, so you may need to experiment with quoting styles + depending on your platform, or you may find the option + --define-from-module more suitable for use. + +
  • +
  • -define-from-module SOMEMODULE — will load the named module (as + per the NodeJS require() function) and iterate all the exported + properties of the module defining them as symbol names to be defined + (as if by the --define option) per the name of each property + (i.e. without the module name prefix) and given the value of the + property. This is a much easier way to handle and document groups of + symbols to be defined rather than a large number of --define + options. + +
  • +
  • --unsafe — enable other additional optimizations that are known to be + unsafe in some contrived situations, but could still be generally useful. + For now only these: + +
      +
    • foo.toString() ==> foo+"" +
    • +
    • new Array(x,…) ==> [x,…] +
    • +
    • new Array(x) ==> Array(x) + +
    • +
    + +
  • +
  • --max-line-len (default 32K characters) — add a newline after around + 32K characters. I've seen both FF and Chrome croak when all the code was + on a single line of around 670K. Pass –max-line-len 0 to disable this + safety feature. + +
  • +
  • --reserved-names — some libraries rely on certain names to be used, as + pointed out in issue #92 and #81, so this option allow you to exclude such + names from the mangler. For example, to keep names require and $super + intact you'd specify –reserved-names "require,$super". + +
  • +
  • --inline-script – when you want to include the output literally in an + HTML <script> tag you can use this option to prevent </script from + showing up in the output. + +
  • +
  • --lift-vars – when you pass this, UglifyJS will apply the following + transformations (see the notes in API, ast_lift_variables): + +
      +
    • put all var declarations at the start of the scope +
    • +
    • make sure a variable is declared only once +
    • +
    • discard unused function arguments +
    • +
    • discard unused inner (named) functions +
    • +
    • finally, try to merge assignments into that one var declaration, if + possible. +
    • +
    + +
  • +
+ + + +
+ +
+

1.4.1 API

+
+ + +

+To use the library from JavaScript, you'd do the following (example for +NodeJS): +

+ + + +
var jsp = require("uglify-js").parser;
+var pro = require("uglify-js").uglify;
+
+var orig_code = "... JS code here";
+var ast = jsp.parse(orig_code); // parse code and get the initial AST
+ast = pro.ast_mangle(ast); // get a new AST with mangled names
+ast = pro.ast_squeeze(ast); // get an AST with compression optimizations
+var final_code = pro.gen_code(ast); // compressed code here
+
+ + +

+The above performs the full compression that is possible right now. As you +can see, there are a sequence of steps which you can apply. For example if +you want compressed output but for some reason you don't want to mangle +variable names, you would simply skip the line that calls +pro.ast_mangle(ast). +

+

+Some of these functions take optional arguments. Here's a description: +

+
    +
  • jsp.parse(code, strict_semicolons) – parses JS code and returns an AST. + strict_semicolons is optional and defaults to false. If you pass + true then the parser will throw an error when it expects a semicolon and + it doesn't find it. For most JS code you don't want that, but it's useful + if you want to strictly sanitize your code. + +
  • +
  • pro.ast_lift_variables(ast) – merge and move var declarations to the + scop of the scope; discard unused function arguments or variables; discard + unused (named) inner functions. It also tries to merge assignments + following the var declaration into it. + +

    + If your code is very hand-optimized concerning var declarations, this + lifting variable declarations might actually increase size. For me it + helps out. On jQuery it adds 865 bytes (243 after gzip). YMMV. Also + note that (since it's not enabled by default) this operation isn't yet + heavily tested (please report if you find issues!). +

    +

    + Note that although it might increase the image size (on jQuery it gains + 865 bytes, 243 after gzip) it's technically more correct: in certain + situations, dead code removal might drop variable declarations, which + would not happen if the variables are lifted in advance. +

    +

    + Here's an example of what it does: +

  • +
+ + + + + +
function f(a, b, c, d, e) {
+    var q;
+    var w;
+    w = 10;
+    q = 20;
+    for (var i = 1; i < 10; ++i) {
+        var boo = foo(a);
+    }
+    for (var i = 0; i < 1; ++i) {
+        var boo = bar(c);
+    }
+    function foo(){ ... }
+    function bar(){ ... }
+    function baz(){ ... }
+}
+
+// transforms into ==>
+
+function f(a, b, c) {
+    var i, boo, w = 10, q = 20;
+    for (i = 1; i < 10; ++i) {
+        boo = foo(a);
+    }
+    for (i = 0; i < 1; ++i) {
+        boo = bar(c);
+    }
+    function foo() { ... }
+    function bar() { ... }
+}
+
+ + +
    +
  • pro.ast_mangle(ast, options) – generates a new AST containing mangled + (compressed) variable and function names. It supports the following + options: + +
      +
    • toplevel – mangle toplevel names (by default we don't touch them). +
    • +
    • except – an array of names to exclude from compression. +
    • +
    • defines – an object with properties named after symbols to + replace (see the --define option for the script) and the values + representing the AST replacement value. + +
    • +
    + +
  • +
  • pro.ast_squeeze(ast, options) – employs further optimizations designed + to reduce the size of the code that gen_code would generate from the + AST. Returns a new AST. options can be a hash; the supported options + are: + +
      +
    • make_seqs (default true) which will cause consecutive statements in a + block to be merged using the "sequence" (comma) operator + +
    • +
    • dead_code (default true) which will remove unreachable code. + +
    • +
    + +
  • +
  • pro.gen_code(ast, options) – generates JS code from the AST. By + default it's minified, but using the options argument you can get nicely + formatted output. options is, well, optional :-) and if you pass it it + must be an object and supports the following properties (below you can see + the default values): + +
      +
    • beautify: false – pass true if you want indented output +
    • +
    • indent_start: 0 (only applies when beautify is true) – initial + indentation in spaces +
    • +
    • indent_level: 4 (only applies when beautify is true) -- + indentation level, in spaces (pass an even number) +
    • +
    • quote_keys: false – if you pass true it will quote all keys in + literal objects +
    • +
    • space_colon: false (only applies when beautify is true) – wether + to put a space before the colon in object literals +
    • +
    • ascii_only: false – pass true if you want to encode non-ASCII + characters as \uXXXX. +
    • +
    • inline_script: false – pass true to escape occurrences of + </script in strings +
    • +
    + +
  • +
+ + +
+ +
+ +
+

1.4.2 Beautifier shortcoming – no more comments

+
+ + +

+The beautifier can be used as a general purpose indentation tool. It's +useful when you want to make a minified file readable. One limitation, +though, is that it discards all comments, so you don't really want to use it +to reformat your code, unless you don't have, or don't care about, comments. +

+

+In fact it's not the beautifier who discards comments — they are dumped at +the parsing stage, when we build the initial AST. Comments don't really +make sense in the AST, and while we could add nodes for them, it would be +inconvenient because we'd have to add special rules to ignore them at all +the processing stages. +

+
+ +
+ +
+

1.4.3 Use as a code pre-processor

+
+ + +

+The --define option can be used, particularly when combined with the +constant folding logic, as a form of pre-processor to enable or remove +particular constructions, such as might be used for instrumenting +development code, or to produce variations aimed at a specific +platform. +

+

+The code below illustrates the way this can be done, and how the +symbol replacement is performed. +

+ + + +
CLAUSE1: if (typeof DEVMODE === 'undefined') {
+    DEVMODE = true;
+}
+
+CLAUSE2: function init() {
+    if (DEVMODE) {
+        console.log("init() called");
+    }
+    ....
+    DEVMODE &amp;&amp; console.log("init() complete");
+}
+
+CLAUSE3: function reportDeviceStatus(device) {
+    var DEVMODE = device.mode, DEVNAME = device.name;
+    if (DEVMODE === 'open') {
+        ....
+    }
+}
+
+ + +

+When the above code is normally executed, the undeclared global +variable DEVMODE will be assigned the value true (see CLAUSE1) +and so the init() function (CLAUSE2) will write messages to the +console log when executed, but in CLAUSE3 a locally declared +variable will mask access to the DEVMODE global symbol. +

+

+If the above code is processed by UglifyJS with an argument of +--define DEVMODE=false then UglifyJS will replace DEVMODE with the +boolean constant value false within CLAUSE1 and CLAUSE2, but it +will leave CLAUSE3 as it stands because there DEVMODE resolves to +a validly declared variable. +

+

+And more so, the constant-folding features of UglifyJS will recognise +that the if condition of CLAUSE1 is thus always false, and so will +remove the test and body of CLAUSE1 altogether (including the +otherwise slightly problematical statement false = true; which it +will have formed by replacing DEVMODE in the body). Similarly, +within CLAUSE2 both calls to console.log() will be removed +altogether. +

+

+In this way you can mimic, to a limited degree, the functionality of +the C/C++ pre-processor to enable or completely remove blocks +depending on how certain symbols are defined - perhaps using UglifyJS +to generate different versions of source aimed at different +environments +

+

+It is recommmended (but not made mandatory) that symbols designed for +this purpose are given names consisting of UPPER_CASE_LETTERS to +distinguish them from other (normal) symbols and avoid the sort of +clash that CLAUSE3 above illustrates. +

+
+
+ +
+ +
+

1.5 Compression – how good is it?

+
+ + +

+Here are updated statistics. (I also updated my Google Closure and YUI +installations). +

+

+We're still a lot better than YUI in terms of compression, though slightly +slower. We're still a lot faster than Closure, and compression after gzip +is comparable. +

+ + ++ + + + + + + + + + +
FileUglifyJSUglifyJS+gzipClosureClosure+gzipYUIYUI+gzip
jquery-1.6.2.js91001 (0:01.59)3189690678 (0:07.40)31979101527 (0:01.82)34646
paper.js142023 (0:01.65)43334134301 (0:07.42)42495173383 (0:01.58)48785
prototype.js88544 (0:01.09)2668086955 (0:06.97)2632692130 (0:00.79)28624
thelib-full.js (DynarchLIB)251939 (0:02.55)72535249911 (0:09.05)72696258869 (0:01.94)76584
+ + +
+ +
+ +
+

1.6 Bugs?

+
+ + +

+Unfortunately, for the time being there is no automated test suite. But I +ran the compressor manually on non-trivial code, and then I tested that the +generated code works as expected. A few hundred times. +

+

+DynarchLIB was started in times when there was no good JS minifier. +Therefore I was quite religious about trying to write short code manually, +and as such DL contains a lot of syntactic hacks1 such as “foo == bar ? a += 10 : b = 20”, though the more readable version would clearly be to use +“if/else”. +

+

+Since the parser/compressor runs fine on DL and jQuery, I'm quite confident +that it's solid enough for production use. If you can identify any bugs, +I'd love to hear about them (use the Google Group or email me directly). +

+
+ +
+ +
+

1.7 Links

+
+ + + + + +
+ +
+ +
+

1.8 License

+
+ + +

+UglifyJS is released under the BSD license: +

+ + + +
Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
+Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+    * Redistributions of source code must retain the above
+      copyright notice, this list of conditions and the following
+      disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials
+      provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+ + +
+

Footnotes:

+
+

1 I even reported a few bugs and suggested some fixes in the original + parse-js library, and Marijn pushed fixes literally in minutes. +

+
+
+ +
+
+
+ +
+

Date: 2011-12-09 14:59:08 EET

+

Author: Mihai Bazon

+

Org version 7.7 with Emacs version 23

+Validate XHTML 1.0 + +
+ + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.org b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.org new file mode 100644 index 00000000..4d01fdfd --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.org @@ -0,0 +1,574 @@ +#+TITLE: UglifyJS -- a JavaScript parser/compressor/beautifier +#+KEYWORDS: javascript, js, parser, compiler, compressor, mangle, minify, minifier +#+DESCRIPTION: a JavaScript parser/compressor/beautifier in JavaScript +#+STYLE: +#+AUTHOR: Mihai Bazon +#+EMAIL: mihai.bazon@gmail.com + +* UglifyJS --- a JavaScript parser/compressor/beautifier + +This package implements a general-purpose JavaScript +parser/compressor/beautifier toolkit. It is developed on [[http://nodejs.org/][NodeJS]], but it +should work on any JavaScript platform supporting the CommonJS module system +(and if your platform of choice doesn't support CommonJS, you can easily +implement it, or discard the =exports.*= lines from UglifyJS sources). + +The tokenizer/parser generates an abstract syntax tree from JS code. You +can then traverse the AST to learn more about the code, or do various +manipulations on it. This part is implemented in [[../lib/parse-js.js][parse-js.js]] and it's a +port to JavaScript of the excellent [[http://marijn.haverbeke.nl/parse-js/][parse-js]] Common Lisp library from [[http://marijn.haverbeke.nl/][Marijn +Haverbeke]]. + +( See [[http://github.com/mishoo/cl-uglify-js][cl-uglify-js]] if you're looking for the Common Lisp version of +UglifyJS. ) + +The second part of this package, implemented in [[../lib/process.js][process.js]], inspects and +manipulates the AST generated by the parser to provide the following: + +- ability to re-generate JavaScript code from the AST. Optionally + indented---you can use this if you want to “beautify” a program that has + been compressed, so that you can inspect the source. But you can also run + our code generator to print out an AST without any whitespace, so you + achieve compression as well. + +- shorten variable names (usually to single characters). Our mangler will + analyze the code and generate proper variable names, depending on scope + and usage, and is smart enough to deal with globals defined elsewhere, or + with =eval()= calls or =with{}= statements. In short, if =eval()= or + =with{}= are used in some scope, then all variables in that scope and any + variables in the parent scopes will remain unmangled, and any references + to such variables remain unmangled as well. + +- various small optimizations that may lead to faster code but certainly + lead to smaller code. Where possible, we do the following: + + - foo["bar"] ==> foo.bar + + - remove block brackets ={}= + + - join consecutive var declarations: + var a = 10; var b = 20; ==> var a=10,b=20; + + - resolve simple constant expressions: 1 +2 * 3 ==> 7. We only do the + replacement if the result occupies less bytes; for example 1/3 would + translate to 0.333333333333, so in this case we don't replace it. + + - consecutive statements in blocks are merged into a sequence; in many + cases, this leaves blocks with a single statement, so then we can remove + the block brackets. + + - various optimizations for IF statements: + + - if (foo) bar(); else baz(); ==> foo?bar():baz(); + - if (!foo) bar(); else baz(); ==> foo?baz():bar(); + - if (foo) bar(); ==> foo&&bar(); + - if (!foo) bar(); ==> foo||bar(); + - if (foo) return bar(); else return baz(); ==> return foo?bar():baz(); + - if (foo) return bar(); else something(); ==> {if(foo)return bar();something()} + + - remove some unreachable code and warn about it (code that follows a + =return=, =throw=, =break= or =continue= statement, except + function/variable declarations). + + - act a limited version of a pre-processor (c.f. the pre-processor of + C/C++) to allow you to safely replace selected global symbols with + specified values. When combined with the optimisations above this can + make UglifyJS operate slightly more like a compilation process, in + that when certain symbols are replaced by constant values, entire code + blocks may be optimised away as unreachable. + +** <> + +The following transformations can in theory break code, although they're +probably safe in most practical cases. To enable them you need to pass the +=--unsafe= flag. + +*** Calls involving the global Array constructor + +The following transformations occur: + +#+BEGIN_SRC js +new Array(1, 2, 3, 4) => [1,2,3,4] +Array(a, b, c) => [a,b,c] +new Array(5) => Array(5) +new Array(a) => Array(a) +#+END_SRC + +These are all safe if the Array name isn't redefined. JavaScript does allow +one to globally redefine Array (and pretty much everything, in fact) but I +personally don't see why would anyone do that. + +UglifyJS does handle the case where Array is redefined locally, or even +globally but with a =function= or =var= declaration. Therefore, in the +following cases UglifyJS *doesn't touch* calls or instantiations of Array: + +#+BEGIN_SRC js +// case 1. globally declared variable + var Array; + new Array(1, 2, 3); + Array(a, b); + + // or (can be declared later) + new Array(1, 2, 3); + var Array; + + // or (can be a function) + new Array(1, 2, 3); + function Array() { ... } + +// case 2. declared in a function + (function(){ + a = new Array(1, 2, 3); + b = Array(5, 6); + var Array; + })(); + + // or + (function(Array){ + return Array(5, 6, 7); + })(); + + // or + (function(){ + return new Array(1, 2, 3, 4); + function Array() { ... } + })(); + + // etc. +#+END_SRC + +*** =obj.toString()= ==> =obj+“”= + +** Install (NPM) + +UglifyJS is now available through NPM --- =npm install uglify-js= should do +the job. + +** Install latest code from GitHub + +#+BEGIN_SRC sh +## clone the repository +mkdir -p /where/you/wanna/put/it +cd /where/you/wanna/put/it +git clone git://github.com/mishoo/UglifyJS.git + +## make the module available to Node +mkdir -p ~/.node_libraries/ +cd ~/.node_libraries/ +ln -s /where/you/wanna/put/it/UglifyJS/uglify-js.js + +## and if you want the CLI script too: +mkdir -p ~/bin +cd ~/bin +ln -s /where/you/wanna/put/it/UglifyJS/bin/uglifyjs + # (then add ~/bin to your $PATH if it's not there already) +#+END_SRC + +** Usage + +There is a command-line tool that exposes the functionality of this library +for your shell-scripting needs: + +#+BEGIN_SRC sh +uglifyjs [ options... ] [ filename ] +#+END_SRC + +=filename= should be the last argument and should name the file from which +to read the JavaScript code. If you don't specify it, it will read code +from STDIN. + +Supported options: + +- =-b= or =--beautify= --- output indented code; when passed, additional + options control the beautifier: + + - =-i N= or =--indent N= --- indentation level (number of spaces) + + - =-q= or =--quote-keys= --- quote keys in literal objects (by default, + only keys that cannot be identifier names will be quotes). + +- =--ascii= --- pass this argument to encode non-ASCII characters as + =\uXXXX= sequences. By default UglifyJS won't bother to do it and will + output Unicode characters instead. (the output is always encoded in UTF8, + but if you pass this option you'll only get ASCII). + +- =-nm= or =--no-mangle= --- don't mangle names. + +- =-nmf= or =--no-mangle-functions= -- in case you want to mangle variable + names, but not touch function names. + +- =-ns= or =--no-squeeze= --- don't call =ast_squeeze()= (which does various + optimizations that result in smaller, less readable code). + +- =-mt= or =--mangle-toplevel= --- mangle names in the toplevel scope too + (by default we don't do this). + +- =--no-seqs= --- when =ast_squeeze()= is called (thus, unless you pass + =--no-squeeze=) it will reduce consecutive statements in blocks into a + sequence. For example, "a = 10; b = 20; foo();" will be written as + "a=10,b=20,foo();". In various occasions, this allows us to discard the + block brackets (since the block becomes a single statement). This is ON + by default because it seems safe and saves a few hundred bytes on some + libs that I tested it on, but pass =--no-seqs= to disable it. + +- =--no-dead-code= --- by default, UglifyJS will remove code that is + obviously unreachable (code that follows a =return=, =throw=, =break= or + =continue= statement and is not a function/variable declaration). Pass + this option to disable this optimization. + +- =-nc= or =--no-copyright= --- by default, =uglifyjs= will keep the initial + comment tokens in the generated code (assumed to be copyright information + etc.). If you pass this it will discard it. + +- =-o filename= or =--output filename= --- put the result in =filename=. If + this isn't given, the result goes to standard output (or see next one). + +- =--overwrite= --- if the code is read from a file (not from STDIN) and you + pass =--overwrite= then the output will be written in the same file. + +- =--ast= --- pass this if you want to get the Abstract Syntax Tree instead + of JavaScript as output. Useful for debugging or learning more about the + internals. + +- =-v= or =--verbose= --- output some notes on STDERR (for now just how long + each operation takes). + +- =-d SYMBOL[=VALUE]= or =--define SYMBOL[=VALUE]= --- will replace + all instances of the specified symbol where used as an identifier + (except where symbol has properly declared by a var declaration or + use as function parameter or similar) with the specified value. This + argument may be specified multiple times to define multiple + symbols - if no value is specified the symbol will be replaced with + the value =true=, or you can specify a numeric value (such as + =1024=), a quoted string value (such as ="object"= or + ='https://github.com'=), or the name of another symbol or keyword + (such as =null= or =document=). + This allows you, for example, to assign meaningful names to key + constant values but discard the symbolic names in the uglified + version for brevity/efficiency, or when used wth care, allows + UglifyJS to operate as a form of *conditional compilation* + whereby defining appropriate values may, by dint of the constant + folding and dead code removal features above, remove entire + superfluous code blocks (e.g. completely remove instrumentation or + trace code for production use). + Where string values are being defined, the handling of quotes are + likely to be subject to the specifics of your command shell + environment, so you may need to experiment with quoting styles + depending on your platform, or you may find the option + =--define-from-module= more suitable for use. + +- =-define-from-module SOMEMODULE= --- will load the named module (as + per the NodeJS =require()= function) and iterate all the exported + properties of the module defining them as symbol names to be defined + (as if by the =--define= option) per the name of each property + (i.e. without the module name prefix) and given the value of the + property. This is a much easier way to handle and document groups of + symbols to be defined rather than a large number of =--define= + options. + +- =--unsafe= --- enable other additional optimizations that are known to be + unsafe in some contrived situations, but could still be generally useful. + For now only these: + + - foo.toString() ==> foo+"" + - new Array(x,...) ==> [x,...] + - new Array(x) ==> Array(x) + +- =--max-line-len= (default 32K characters) --- add a newline after around + 32K characters. I've seen both FF and Chrome croak when all the code was + on a single line of around 670K. Pass --max-line-len 0 to disable this + safety feature. + +- =--reserved-names= --- some libraries rely on certain names to be used, as + pointed out in issue #92 and #81, so this option allow you to exclude such + names from the mangler. For example, to keep names =require= and =$super= + intact you'd specify --reserved-names "require,$super". + +- =--inline-script= -- when you want to include the output literally in an + HTML =\n\n\n\n\n
\n\n
\n\n
\n

UglifyJS – a JavaScript parser/compressor/beautifier

\n\n\n\n\n
\n

1 UglifyJS — a JavaScript parser/compressor/beautifier

\n
\n\n\n

\nThis package implements a general-purpose JavaScript\nparser/compressor/beautifier toolkit. It is developed on NodeJS, but it\nshould work on any JavaScript platform supporting the CommonJS module system\n(and if your platform of choice doesn't support CommonJS, you can easily\nimplement it, or discard the exports.* lines from UglifyJS sources).\n

\n

\nThe tokenizer/parser generates an abstract syntax tree from JS code. You\ncan then traverse the AST to learn more about the code, or do various\nmanipulations on it. This part is implemented in parse-js.js and it's a\nport to JavaScript of the excellent parse-js Common Lisp library from Marijn Haverbeke.\n

\n

\n( See cl-uglify-js if you're looking for the Common Lisp version of\nUglifyJS. )\n

\n

\nThe second part of this package, implemented in process.js, inspects and\nmanipulates the AST generated by the parser to provide the following:\n

\n
    \n
  • ability to re-generate JavaScript code from the AST. Optionally\n indented—you can use this if you want to “beautify” a program that has\n been compressed, so that you can inspect the source. But you can also run\n our code generator to print out an AST without any whitespace, so you\n achieve compression as well.\n\n
  • \n
  • shorten variable names (usually to single characters). Our mangler will\n analyze the code and generate proper variable names, depending on scope\n and usage, and is smart enough to deal with globals defined elsewhere, or\n with eval() calls or with{} statements. In short, if eval() or\n with{} are used in some scope, then all variables in that scope and any\n variables in the parent scopes will remain unmangled, and any references\n to such variables remain unmangled as well.\n\n
  • \n
  • various small optimizations that may lead to faster code but certainly\n lead to smaller code. Where possible, we do the following:\n\n
      \n
    • foo[\"bar\"] ==> foo.bar\n\n
    • \n
    • remove block brackets {}\n\n
    • \n
    • join consecutive var declarations:\n var a = 10; var b = 20; ==> var a=10,b=20;\n\n
    • \n
    • resolve simple constant expressions: 1 +2 * 3 ==> 7. We only do the\n replacement if the result occupies less bytes; for example 1/3 would\n translate to 0.333333333333, so in this case we don't replace it.\n\n
    • \n
    • consecutive statements in blocks are merged into a sequence; in many\n cases, this leaves blocks with a single statement, so then we can remove\n the block brackets.\n\n
    • \n
    • various optimizations for IF statements:\n\n
        \n
      • if (foo) bar(); else baz(); ==> foo?bar():baz();\n
      • \n
      • if (!foo) bar(); else baz(); ==> foo?baz():bar();\n
      • \n
      • if (foo) bar(); ==> foo&&bar();\n
      • \n
      • if (!foo) bar(); ==> foo||bar();\n
      • \n
      • if (foo) return bar(); else return baz(); ==> return foo?bar():baz();\n
      • \n
      • if (foo) return bar(); else something(); ==> {if(foo)return bar();something()}\n\n
      • \n
      \n\n
    • \n
    • remove some unreachable code and warn about it (code that follows a\n return, throw, break or continue statement, except\n function/variable declarations).\n\n
    • \n
    • act a limited version of a pre-processor (c.f. the pre-processor of\n C/C++) to allow you to safely replace selected global symbols with\n specified values. When combined with the optimisations above this can\n make UglifyJS operate slightly more like a compilation process, in\n that when certain symbols are replaced by constant values, entire code\n blocks may be optimised away as unreachable.\n
    • \n
    \n\n
  • \n
\n\n\n\n
\n\n
\n

1.1 Unsafe transformations

\n
\n\n\n

\nThe following transformations can in theory break code, although they're\nprobably safe in most practical cases. To enable them you need to pass the\n--unsafe flag.\n

\n\n
\n\n
\n

1.1.1 Calls involving the global Array constructor

\n
\n\n\n

\nThe following transformations occur:\n

\n\n\n\n
new Array(1, 2, 3, 4)  => [1,2,3,4]\nArray(a, b, c)         => [a,b,c]\nnew Array(5)           => Array(5)\nnew Array(a)           => Array(a)\n
\n\n\n

\nThese are all safe if the Array name isn't redefined. JavaScript does allow\none to globally redefine Array (and pretty much everything, in fact) but I\npersonally don't see why would anyone do that.\n

\n

\nUglifyJS does handle the case where Array is redefined locally, or even\nglobally but with a function or var declaration. Therefore, in the\nfollowing cases UglifyJS doesn't touch calls or instantiations of Array:\n

\n\n\n\n
// case 1.  globally declared variable\n  var Array;\n  new Array(1, 2, 3);\n  Array(a, b);\n\n  // or (can be declared later)\n  new Array(1, 2, 3);\n  var Array;\n\n  // or (can be a function)\n  new Array(1, 2, 3);\n  function Array() { ... }\n\n// case 2.  declared in a function\n  (function(){\n    a = new Array(1, 2, 3);\n    b = Array(5, 6);\n    var Array;\n  })();\n\n  // or\n  (function(Array){\n    return Array(5, 6, 7);\n  })();\n\n  // or\n  (function(){\n    return new Array(1, 2, 3, 4);\n    function Array() { ... }\n  })();\n\n  // etc.\n
\n\n\n
\n\n
\n\n
\n

1.1.2 obj.toString() ==> obj+“”

\n
\n\n\n
\n
\n\n
\n\n
\n

1.2 Install (NPM)

\n
\n\n\n

\nUglifyJS is now available through NPM — npm install uglify-js should do\nthe job.\n

\n
\n\n
\n\n
\n

1.3 Install latest code from GitHub

\n
\n\n\n\n\n\n
## clone the repository\nmkdir -p /where/you/wanna/put/it\ncd /where/you/wanna/put/it\ngit clone git://github.com/mishoo/UglifyJS.git\n\n## make the module available to Node\nmkdir -p ~/.node_libraries/\ncd ~/.node_libraries/\nln -s /where/you/wanna/put/it/UglifyJS/uglify-js.js\n\n## and if you want the CLI script too:\nmkdir -p ~/bin\ncd ~/bin\nln -s /where/you/wanna/put/it/UglifyJS/bin/uglifyjs\n  # (then add ~/bin to your $PATH if it's not there already)\n
\n\n\n
\n\n
\n\n
\n

1.4 Usage

\n
\n\n\n

\nThere is a command-line tool that exposes the functionality of this library\nfor your shell-scripting needs:\n

\n\n\n\n
uglifyjs [ options... ] [ filename ]\n
\n\n\n

\nfilename should be the last argument and should name the file from which\nto read the JavaScript code. If you don't specify it, it will read code\nfrom STDIN.\n

\n

\nSupported options:\n

\n
    \n
  • -b or --beautify — output indented code; when passed, additional\n options control the beautifier:\n\n
      \n
    • -i N or --indent N — indentation level (number of spaces)\n\n
    • \n
    • -q or --quote-keys — quote keys in literal objects (by default,\n only keys that cannot be identifier names will be quotes).\n\n
    • \n
    \n\n
  • \n
  • --ascii — pass this argument to encode non-ASCII characters as\n \\uXXXX sequences. By default UglifyJS won't bother to do it and will\n output Unicode characters instead. (the output is always encoded in UTF8,\n but if you pass this option you'll only get ASCII).\n\n
  • \n
  • -nm or --no-mangle — don't mangle names.\n\n
  • \n
  • -nmf or --no-mangle-functions – in case you want to mangle variable\n names, but not touch function names.\n\n
  • \n
  • -ns or --no-squeeze — don't call ast_squeeze() (which does various\n optimizations that result in smaller, less readable code).\n\n
  • \n
  • -mt or --mangle-toplevel — mangle names in the toplevel scope too\n (by default we don't do this).\n\n
  • \n
  • --no-seqs — when ast_squeeze() is called (thus, unless you pass\n --no-squeeze) it will reduce consecutive statements in blocks into a\n sequence. For example, \"a = 10; b = 20; foo();\" will be written as\n \"a=10,b=20,foo();\". In various occasions, this allows us to discard the\n block brackets (since the block becomes a single statement). This is ON\n by default because it seems safe and saves a few hundred bytes on some\n libs that I tested it on, but pass --no-seqs to disable it.\n\n
  • \n
  • --no-dead-code — by default, UglifyJS will remove code that is\n obviously unreachable (code that follows a return, throw, break or\n continue statement and is not a function/variable declaration). Pass\n this option to disable this optimization.\n\n
  • \n
  • -nc or --no-copyright — by default, uglifyjs will keep the initial\n comment tokens in the generated code (assumed to be copyright information\n etc.). If you pass this it will discard it.\n\n
  • \n
  • -o filename or --output filename — put the result in filename. If\n this isn't given, the result goes to standard output (or see next one).\n\n
  • \n
  • --overwrite — if the code is read from a file (not from STDIN) and you\n pass --overwrite then the output will be written in the same file.\n\n
  • \n
  • --ast — pass this if you want to get the Abstract Syntax Tree instead\n of JavaScript as output. Useful for debugging or learning more about the\n internals.\n\n
  • \n
  • -v or --verbose — output some notes on STDERR (for now just how long\n each operation takes).\n\n
  • \n
  • -d SYMBOL[=VALUE] or --define SYMBOL[=VALUE] — will replace\n all instances of the specified symbol where used as an identifier\n (except where symbol has properly declared by a var declaration or\n use as function parameter or similar) with the specified value. This\n argument may be specified multiple times to define multiple\n symbols - if no value is specified the symbol will be replaced with\n the value true, or you can specify a numeric value (such as\n 1024), a quoted string value (such as =\"object\"= or\n ='https://github.com'), or the name of another symbol or keyword (such as =null or document).\n This allows you, for example, to assign meaningful names to key\n constant values but discard the symbolic names in the uglified\n version for brevity/efficiency, or when used wth care, allows\n UglifyJS to operate as a form of conditional compilation\n whereby defining appropriate values may, by dint of the constant\n folding and dead code removal features above, remove entire\n superfluous code blocks (e.g. completely remove instrumentation or\n trace code for production use).\n Where string values are being defined, the handling of quotes are\n likely to be subject to the specifics of your command shell\n environment, so you may need to experiment with quoting styles\n depending on your platform, or you may find the option\n --define-from-module more suitable for use.\n\n
  • \n
  • -define-from-module SOMEMODULE — will load the named module (as\n per the NodeJS require() function) and iterate all the exported\n properties of the module defining them as symbol names to be defined\n (as if by the --define option) per the name of each property\n (i.e. without the module name prefix) and given the value of the\n property. This is a much easier way to handle and document groups of\n symbols to be defined rather than a large number of --define\n options.\n\n
  • \n
  • --unsafe — enable other additional optimizations that are known to be\n unsafe in some contrived situations, but could still be generally useful.\n For now only these:\n\n
      \n
    • foo.toString() ==> foo+\"\"\n
    • \n
    • new Array(x,…) ==> [x,…]\n
    • \n
    • new Array(x) ==> Array(x)\n\n
    • \n
    \n\n
  • \n
  • --max-line-len (default 32K characters) — add a newline after around\n 32K characters. I've seen both FF and Chrome croak when all the code was\n on a single line of around 670K. Pass –max-line-len 0 to disable this\n safety feature.\n\n
  • \n
  • --reserved-names — some libraries rely on certain names to be used, as\n pointed out in issue #92 and #81, so this option allow you to exclude such\n names from the mangler. For example, to keep names require and $super\n intact you'd specify –reserved-names \"require,$super\".\n\n
  • \n
  • --inline-script – when you want to include the output literally in an\n HTML <script> tag you can use this option to prevent </script from\n showing up in the output.\n\n
  • \n
  • --lift-vars – when you pass this, UglifyJS will apply the following\n transformations (see the notes in API, ast_lift_variables):\n\n
      \n
    • put all var declarations at the start of the scope\n
    • \n
    • make sure a variable is declared only once\n
    • \n
    • discard unused function arguments\n
    • \n
    • discard unused inner (named) functions\n
    • \n
    • finally, try to merge assignments into that one var declaration, if\n possible.\n
    • \n
    \n\n
  • \n
\n\n\n\n
\n\n
\n

1.4.1 API

\n
\n\n\n

\nTo use the library from JavaScript, you'd do the following (example for\nNodeJS):\n

\n\n\n\n
var jsp = require(\"uglify-js\").parser;\nvar pro = require(\"uglify-js\").uglify;\n\nvar orig_code = \"... JS code here\";\nvar ast = jsp.parse(orig_code); // parse code and get the initial AST\nast = pro.ast_mangle(ast); // get a new AST with mangled names\nast = pro.ast_squeeze(ast); // get an AST with compression optimizations\nvar final_code = pro.gen_code(ast); // compressed code here\n
\n\n\n

\nThe above performs the full compression that is possible right now. As you\ncan see, there are a sequence of steps which you can apply. For example if\nyou want compressed output but for some reason you don't want to mangle\nvariable names, you would simply skip the line that calls\npro.ast_mangle(ast).\n

\n

\nSome of these functions take optional arguments. Here's a description:\n

\n
    \n
  • jsp.parse(code, strict_semicolons) – parses JS code and returns an AST.\n strict_semicolons is optional and defaults to false. If you pass\n true then the parser will throw an error when it expects a semicolon and\n it doesn't find it. For most JS code you don't want that, but it's useful\n if you want to strictly sanitize your code.\n\n
  • \n
  • pro.ast_lift_variables(ast) – merge and move var declarations to the\n scop of the scope; discard unused function arguments or variables; discard\n unused (named) inner functions. It also tries to merge assignments\n following the var declaration into it.\n\n

    \n If your code is very hand-optimized concerning var declarations, this\n lifting variable declarations might actually increase size. For me it\n helps out. On jQuery it adds 865 bytes (243 after gzip). YMMV. Also\n note that (since it's not enabled by default) this operation isn't yet\n heavily tested (please report if you find issues!).\n

    \n

    \n Note that although it might increase the image size (on jQuery it gains\n 865 bytes, 243 after gzip) it's technically more correct: in certain\n situations, dead code removal might drop variable declarations, which\n would not happen if the variables are lifted in advance.\n

    \n

    \n Here's an example of what it does:\n

  • \n
\n\n\n\n\n\n
function f(a, b, c, d, e) {\n    var q;\n    var w;\n    w = 10;\n    q = 20;\n    for (var i = 1; i < 10; ++i) {\n        var boo = foo(a);\n    }\n    for (var i = 0; i < 1; ++i) {\n        var boo = bar(c);\n    }\n    function foo(){ ... }\n    function bar(){ ... }\n    function baz(){ ... }\n}\n\n// transforms into ==>\n\nfunction f(a, b, c) {\n    var i, boo, w = 10, q = 20;\n    for (i = 1; i < 10; ++i) {\n        boo = foo(a);\n    }\n    for (i = 0; i < 1; ++i) {\n        boo = bar(c);\n    }\n    function foo() { ... }\n    function bar() { ... }\n}\n
\n\n\n
    \n
  • pro.ast_mangle(ast, options) – generates a new AST containing mangled\n (compressed) variable and function names. It supports the following\n options:\n\n
      \n
    • toplevel – mangle toplevel names (by default we don't touch them).\n
    • \n
    • except – an array of names to exclude from compression.\n
    • \n
    • defines – an object with properties named after symbols to\n replace (see the --define option for the script) and the values\n representing the AST replacement value.\n\n
    • \n
    \n\n
  • \n
  • pro.ast_squeeze(ast, options) – employs further optimizations designed\n to reduce the size of the code that gen_code would generate from the\n AST. Returns a new AST. options can be a hash; the supported options\n are:\n\n
      \n
    • make_seqs (default true) which will cause consecutive statements in a\n block to be merged using the \"sequence\" (comma) operator\n\n
    • \n
    • dead_code (default true) which will remove unreachable code.\n\n
    • \n
    \n\n
  • \n
  • pro.gen_code(ast, options) – generates JS code from the AST. By\n default it's minified, but using the options argument you can get nicely\n formatted output. options is, well, optional :-) and if you pass it it\n must be an object and supports the following properties (below you can see\n the default values):\n\n
      \n
    • beautify: false – pass true if you want indented output\n
    • \n
    • indent_start: 0 (only applies when beautify is true) – initial\n indentation in spaces\n
    • \n
    • indent_level: 4 (only applies when beautify is true) --\n indentation level, in spaces (pass an even number)\n
    • \n
    • quote_keys: false – if you pass true it will quote all keys in\n literal objects\n
    • \n
    • space_colon: false (only applies when beautify is true) – wether\n to put a space before the colon in object literals\n
    • \n
    • ascii_only: false – pass true if you want to encode non-ASCII\n characters as \\uXXXX.\n
    • \n
    • inline_script: false – pass true to escape occurrences of\n </script in strings\n
    • \n
    \n\n
  • \n
\n\n\n
\n\n
\n\n
\n

1.4.2 Beautifier shortcoming – no more comments

\n
\n\n\n

\nThe beautifier can be used as a general purpose indentation tool. It's\nuseful when you want to make a minified file readable. One limitation,\nthough, is that it discards all comments, so you don't really want to use it\nto reformat your code, unless you don't have, or don't care about, comments.\n

\n

\nIn fact it's not the beautifier who discards comments — they are dumped at\nthe parsing stage, when we build the initial AST. Comments don't really\nmake sense in the AST, and while we could add nodes for them, it would be\ninconvenient because we'd have to add special rules to ignore them at all\nthe processing stages.\n

\n
\n\n
\n\n
\n

1.4.3 Use as a code pre-processor

\n
\n\n\n

\nThe --define option can be used, particularly when combined with the\nconstant folding logic, as a form of pre-processor to enable or remove\nparticular constructions, such as might be used for instrumenting\ndevelopment code, or to produce variations aimed at a specific\nplatform.\n

\n

\nThe code below illustrates the way this can be done, and how the\nsymbol replacement is performed.\n

\n\n\n\n
CLAUSE1: if (typeof DEVMODE === 'undefined') {\n    DEVMODE = true;\n}\n\nCLAUSE2: function init() {\n    if (DEVMODE) {\n        console.log(\"init() called\");\n    }\n    ....\n    DEVMODE &amp;&amp; console.log(\"init() complete\");\n}\n\nCLAUSE3: function reportDeviceStatus(device) {\n    var DEVMODE = device.mode, DEVNAME = device.name;\n    if (DEVMODE === 'open') {\n        ....\n    }\n}\n
\n\n\n

\nWhen the above code is normally executed, the undeclared global\nvariable DEVMODE will be assigned the value true (see CLAUSE1)\nand so the init() function (CLAUSE2) will write messages to the\nconsole log when executed, but in CLAUSE3 a locally declared\nvariable will mask access to the DEVMODE global symbol.\n

\n

\nIf the above code is processed by UglifyJS with an argument of\n--define DEVMODE=false then UglifyJS will replace DEVMODE with the\nboolean constant value false within CLAUSE1 and CLAUSE2, but it\nwill leave CLAUSE3 as it stands because there DEVMODE resolves to\na validly declared variable.\n

\n

\nAnd more so, the constant-folding features of UglifyJS will recognise\nthat the if condition of CLAUSE1 is thus always false, and so will\nremove the test and body of CLAUSE1 altogether (including the\notherwise slightly problematical statement false = true; which it\nwill have formed by replacing DEVMODE in the body). Similarly,\nwithin CLAUSE2 both calls to console.log() will be removed\naltogether.\n

\n

\nIn this way you can mimic, to a limited degree, the functionality of\nthe C/C++ pre-processor to enable or completely remove blocks\ndepending on how certain symbols are defined - perhaps using UglifyJS\nto generate different versions of source aimed at different\nenvironments\n

\n

\nIt is recommmended (but not made mandatory) that symbols designed for\nthis purpose are given names consisting of UPPER_CASE_LETTERS to\ndistinguish them from other (normal) symbols and avoid the sort of\nclash that CLAUSE3 above illustrates.\n

\n
\n
\n\n
\n\n
\n

1.5 Compression – how good is it?

\n
\n\n\n

\nHere are updated statistics. (I also updated my Google Closure and YUI\ninstallations).\n

\n

\nWe're still a lot better than YUI in terms of compression, though slightly\nslower. We're still a lot faster than Closure, and compression after gzip\nis comparable.\n

\n\n\n\n\n\n\n\n\n\n\n\n\n\n
FileUglifyJSUglifyJS+gzipClosureClosure+gzipYUIYUI+gzip
jquery-1.6.2.js91001 (0:01.59)3189690678 (0:07.40)31979101527 (0:01.82)34646
paper.js142023 (0:01.65)43334134301 (0:07.42)42495173383 (0:01.58)48785
prototype.js88544 (0:01.09)2668086955 (0:06.97)2632692130 (0:00.79)28624
thelib-full.js (DynarchLIB)251939 (0:02.55)72535249911 (0:09.05)72696258869 (0:01.94)76584
\n\n\n
\n\n
\n\n
\n

1.6 Bugs?

\n
\n\n\n

\nUnfortunately, for the time being there is no automated test suite. But I\nran the compressor manually on non-trivial code, and then I tested that the\ngenerated code works as expected. A few hundred times.\n

\n

\nDynarchLIB was started in times when there was no good JS minifier.\nTherefore I was quite religious about trying to write short code manually,\nand as such DL contains a lot of syntactic hacks1 such as “foo == bar ? a\n= 10 : b = 20”, though the more readable version would clearly be to use\n“if/else”.\n

\n

\nSince the parser/compressor runs fine on DL and jQuery, I'm quite confident\nthat it's solid enough for production use. If you can identify any bugs,\nI'd love to hear about them (use the Google Group or email me directly).\n

\n
\n\n
\n\n
\n

1.7 Links

\n
\n\n\n\n\n\n
\n\n
\n\n
\n

1.8 License

\n
\n\n\n

\nUglifyJS is released under the BSD license:\n

\n\n\n\n
Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>\nBased on parse-js (http://marijn.haverbeke.nl/parse-js/).\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n    * Redistributions of source code must retain the above\n      copyright notice, this list of conditions and the following\n      disclaimer.\n\n    * Redistributions in binary form must reproduce the above\n      copyright notice, this list of conditions and the following\n      disclaimer in the documentation and/or other materials\n      provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY\nEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\nPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\nTORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF\nTHE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n
\n\n\n
\n

Footnotes:

\n
\n

1 I even reported a few bugs and suggested some fixes in the original\n parse-js library, and Marijn pushed fixes literally in minutes.\n

\n
\n
\n\n
\n
\n
\n\n
\n

Date: 2011-12-09 14:59:08 EET

\n

Author: Mihai Bazon

\n

Org version 7.7 with Emacs version 23

\nValidate XHTML 1.0\n\n
\n\n\n", + "readmeFilename": "README.html", + "bugs": { + "url": "https://github.com/mishoo/UglifyJS/issues" + }, + "homepage": "https://github.com/mishoo/UglifyJS", + "_id": "uglify-js@1.2.5", + "_from": "uglify-js@1.2.5" +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/package.json~ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/package.json~ new file mode 100644 index 00000000..e4cb23d5 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/package.json~ @@ -0,0 +1,24 @@ +{ + "name" : "uglify-js", + + "description" : "JavaScript parser and compressor/beautifier toolkit", + + "author" : { + "name" : "Mihai Bazon", + "email" : "mihai.bazon@gmail.com", + "url" : "http://mihai.bazon.net/blog" + }, + + "version" : "1.2.3", + + "main" : "./uglify-js.js", + + "bin" : { + "uglifyjs" : "./bin/uglifyjs" + }, + + "repository": { + "type": "git", + "url": "git@github.com:mishoo/UglifyJS.git" + } +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/beautify.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/beautify.js new file mode 100755 index 00000000..f19369e3 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/beautify.js @@ -0,0 +1,28 @@ +#! /usr/bin/env node + +global.sys = require("sys"); +var fs = require("fs"); + +var jsp = require("../lib/parse-js"); +var pro = require("../lib/process"); + +var filename = process.argv[2]; +fs.readFile(filename, "utf8", function(err, text){ + try { + var ast = time_it("parse", function(){ return jsp.parse(text); }); + ast = time_it("mangle", function(){ return pro.ast_mangle(ast); }); + ast = time_it("squeeze", function(){ return pro.ast_squeeze(ast); }); + var gen = time_it("generate", function(){ return pro.gen_code(ast, false); }); + sys.puts(gen); + } catch(ex) { + sys.debug(ex.stack); + sys.debug(sys.inspect(ex)); + sys.debug(JSON.stringify(ex)); + } +}); + +function time_it(name, cont) { + var t1 = new Date().getTime(); + try { return cont(); } + finally { sys.debug("// " + name + ": " + ((new Date().getTime() - t1) / 1000).toFixed(3) + " sec."); } +}; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/testparser.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/testparser.js new file mode 100755 index 00000000..02c19a9c --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/testparser.js @@ -0,0 +1,403 @@ +#! /usr/bin/env node + +var parseJS = require("../lib/parse-js"); +var sys = require("sys"); + +// write debug in a very straightforward manner +var debug = function(){ + sys.log(Array.prototype.slice.call(arguments).join(', ')); +}; + +ParserTestSuite(function(i, input, desc){ + try { + parseJS.parse(input); + debug("ok " + i + ": " + desc); + } catch(e){ + debug("FAIL " + i + " " + desc + " (" + e + ")"); + } +}); + +function ParserTestSuite(callback){ + var inps = [ + ["var abc;", "Regular variable statement w/o assignment"], + ["var abc = 5;", "Regular variable statement with assignment"], + ["/* */;", "Multiline comment"], + ['/** **/;', 'Double star multiline comment'], + ["var f = function(){;};", "Function expression in var assignment"], + ['hi; // moo\n;', 'single line comment'], + ['var varwithfunction;', 'Dont match keywords as substrings'], // difference between `var withsomevar` and `"str"` (local search and lits) + ['a + b;', 'addition'], + ["'a';", 'single string literal'], + ["'a\\n';", 'single string literal with escaped return'], + ['"a";', 'double string literal'], + ['"a\\n";', 'double string literal with escaped return'], + ['"var";', 'string is a keyword'], + ['"variable";', 'string starts with a keyword'], + ['"somevariable";', 'string contains a keyword'], + ['"somevar";', 'string ends with a keyword'], + ['500;', 'int literal'], + ['500.;', 'float literal w/o decimals'], + ['500.432;', 'float literal with decimals'], + ['.432432;', 'float literal w/o int'], + ['(a,b,c);', 'parens and comma'], + ['[1,2,abc];', 'array literal'], + ['var o = {a:1};', 'object literal unquoted key'], + ['var o = {"b":2};', 'object literal quoted key'], // opening curly may not be at the start of a statement... + ['var o = {c:c};', 'object literal keyname is identifier'], + ['var o = {a:1,"b":2,c:c};', 'object literal combinations'], + ['var x;\nvar y;', 'two lines'], + ['var x;\nfunction n(){; }', 'function def'], + ['var x;\nfunction n(abc){; }', 'function def with arg'], + ['var x;\nfunction n(abc, def){ ;}', 'function def with args'], + ['function n(){ "hello"; }', 'function def with body'], + ['/a/;', 'regex literal'], + ['/a/b;', 'regex literal with flag'], + ['/a/ / /b/;', 'regex div regex'], + ['a/b/c;', 'triple division looks like regex'], + ['+function(){/regex/;};', 'regex at start of function body'], + // http://code.google.com/p/es-lab/source/browse/trunk/tests/parser/parsertests.js?r=86 + // http://code.google.com/p/es-lab/source/browse/trunk/tests/parser/parsertests.js?r=430 + + // first tests for the lexer, should also parse as program (when you append a semi) + + // comments + ['//foo!@#^&$1234\nbar;', 'single line comment'], + ['/* abcd!@#@$* { } && null*/;', 'single line multi line comment'], + ['/*foo\nbar*/;','multi line comment'], + ['/*x*x*/;','multi line comment with *'], + ['/**/;','empty comment'], + // identifiers + ["x;",'1 identifier'], + ["_x;",'2 identifier'], + ["xyz;",'3 identifier'], + ["$x;",'4 identifier'], + ["x$;",'5 identifier'], + ["_;",'6 identifier'], + ["x5;",'7 identifier'], + ["x_y;",'8 identifier'], + ["x+5;",'9 identifier'], + ["xyz123;",'10 identifier'], + ["x1y1z1;",'11 identifier'], + ["foo\\u00D8bar;",'12 identifier unicode escape'], + //["foo�bar;",'13 identifier unicode embedded (might fail)'], + // numbers + ["5;", '1 number'], + ["5.5;", '2 number'], + ["0;", '3 number'], + ["0.0;", '4 number'], + ["0.001;", '5 number'], + ["1.e2;", '6 number'], + ["1.e-2;", '7 number'], + ["1.E2;", '8 number'], + ["1.E-2;", '9 number'], + [".5;", '10 number'], + [".5e3;", '11 number'], + [".5e-3;", '12 number'], + ["0.5e3;", '13 number'], + ["55;", '14 number'], + ["123;", '15 number'], + ["55.55;", '16 number'], + ["55.55e10;", '17 number'], + ["123.456;", '18 number'], + ["1+e;", '20 number'], + ["0x01;", '22 number'], + ["0XCAFE;", '23 number'], + ["0x12345678;", '24 number'], + ["0x1234ABCD;", '25 number'], + ["0x0001;", '26 number'], + // strings + ["\"foo\";", '1 string'], + ["\'foo\';", '2 string'], + ["\"x\";", '3 string'], + ["\'\';", '4 string'], + ["\"foo\\tbar\";", '5 string'], + ["\"!@#$%^&*()_+{}[]\";", '6 string'], + ["\"/*test*/\";", '7 string'], + ["\"//test\";", '8 string'], + ["\"\\\\\";", '9 string'], + ["\"\\u0001\";", '10 string'], + ["\"\\uFEFF\";", '11 string'], + ["\"\\u10002\";", '12 string'], + ["\"\\x55\";", '13 string'], + ["\"\\x55a\";", '14 string'], + ["\"a\\\\nb\";", '15 string'], + ['";"', '16 string: semi in a string'], + ['"a\\\nb";', '17 string: line terminator escape'], + // literals + ["null;", "null"], + ["true;", "true"], + ["false;", "false"], + // regex + ["/a/;", "1 regex"], + ["/abc/;", "2 regex"], + ["/abc[a-z]*def/g;", "3 regex"], + ["/\\b/;", "4 regex"], + ["/[a-zA-Z]/;", "5 regex"], + + // program tests (for as far as they havent been covered above) + + // regexp + ["/foo(.*)/g;", "another regexp"], + // arrays + ["[];", "1 array"], + ["[ ];", "2 array"], + ["[1];", "3 array"], + ["[1,2];", "4 array"], + ["[1,2,,];", "5 array"], + ["[1,2,3];", "6 array"], + ["[1,2,3,,,];", "7 array"], + // objects + ["{};", "1 object"], + ["({x:5});", "2 object"], + ["({x:5,y:6});", "3 object"], + ["({x:5,});", "4 object"], + ["({if:5});", "5 object"], + ["({ get x() {42;} });", "6 object"], + ["({ set y(a) {1;} });", "7 object"], + // member expression + ["o.m;", "1 member expression"], + ["o['m'];", "2 member expression"], + ["o['n']['m'];", "3 member expression"], + ["o.n.m;", "4 member expression"], + ["o.if;", "5 member expression"], + // call and invoke expressions + ["f();", "1 call/invoke expression"], + ["f(x);", "2 call/invoke expression"], + ["f(x,y);", "3 call/invoke expression"], + ["o.m();", "4 call/invoke expression"], + ["o['m'];", "5 call/invoke expression"], + ["o.m(x);", "6 call/invoke expression"], + ["o['m'](x);", "7 call/invoke expression"], + ["o.m(x,y);", "8 call/invoke expression"], + ["o['m'](x,y);", "9 call/invoke expression"], + ["f(x)(y);", "10 call/invoke expression"], + ["f().x;", "11 call/invoke expression"], + + // eval + ["eval('x');", "1 eval"], + ["(eval)('x');", "2 eval"], + ["(1,eval)('x');", "3 eval"], + ["eval(x,y);", "4 eval"], + // new expression + ["new f();", "1 new expression"], + ["new o;", "2 new expression"], + ["new o.m;", "3 new expression"], + ["new o.m(x);", "4 new expression"], + ["new o.m(x,y);", "5 new expression"], + // prefix/postfix + ["++x;", "1 pre/postfix"], + ["x++;", "2 pre/postfix"], + ["--x;", "3 pre/postfix"], + ["x--;", "4 pre/postfix"], + ["x ++;", "5 pre/postfix"], + ["x /* comment */ ++;", "6 pre/postfix"], + ["++ /* comment */ x;", "7 pre/postfix"], + // unary operators + ["delete x;", "1 unary operator"], + ["void x;", "2 unary operator"], + ["+ x;", "3 unary operator"], + ["-x;", "4 unary operator"], + ["~x;", "5 unary operator"], + ["!x;", "6 unary operator"], + // meh + ["new Date++;", "new date ++"], + ["+x++;", " + x ++"], + // expression expressions + ["1 * 2;", "1 expression expressions"], + ["1 / 2;", "2 expression expressions"], + ["1 % 2;", "3 expression expressions"], + ["1 + 2;", "4 expression expressions"], + ["1 - 2;", "5 expression expressions"], + ["1 << 2;", "6 expression expressions"], + ["1 >>> 2;", "7 expression expressions"], + ["1 >> 2;", "8 expression expressions"], + ["1 * 2 + 3;", "9 expression expressions"], + ["(1+2)*3;", "10 expression expressions"], + ["1*(2+3);", "11 expression expressions"], + ["xy;", "13 expression expressions"], + ["x<=y;", "14 expression expressions"], + ["x>=y;", "15 expression expressions"], + ["x instanceof y;", "16 expression expressions"], + ["x in y;", "17 expression expressions"], + ["x&y;", "18 expression expressions"], + ["x^y;", "19 expression expressions"], + ["x|y;", "20 expression expressions"], + ["x+y>>= y;", "1 assignment"], + ["x <<= y;", "2 assignment"], + ["x = y;", "3 assignment"], + ["x += y;", "4 assignment"], + ["x /= y;", "5 assignment"], + // comma + ["x, y;", "comma"], + // block + ["{};", "1 block"], + ["{x;};", "2 block"], + ["{x;y;};", "3 block"], + // vars + ["var x;", "1 var"], + ["var x,y;", "2 var"], + ["var x=1,y=2;", "3 var"], + ["var x,y=2;", "4 var"], + // empty + [";", "1 empty"], + ["\n;", "2 empty"], + // expression statement + ["x;", "1 expression statement"], + ["5;", "2 expression statement"], + ["1+2;", "3 expression statement"], + // if + ["if (c) x; else y;", "1 if statement"], + ["if (c) x;", "2 if statement"], + ["if (c) {} else {};", "3 if statement"], + ["if (c1) if (c2) s1; else s2;", "4 if statement"], + // while + ["do s; while (e);", "1 while statement"], + ["do { s; } while (e);", "2 while statement"], + ["while (e) s;", "3 while statement"], + ["while (e) { s; };", "4 while statement"], + // for + ["for (;;) ;", "1 for statement"], + ["for (;c;x++) x;", "2 for statement"], + ["for (i;i> 1; +var c = 8 >>> 1; \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue34.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue34.js new file mode 100644 index 00000000..022f7a31 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue34.js @@ -0,0 +1,3 @@ +var a = {}; +a["this"] = 1; +a["that"] = 2; \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue4.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue4.js new file mode 100644 index 00000000..0b761037 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue4.js @@ -0,0 +1,3 @@ +var a = 2e3; +var b = 2e-3; +var c = 2e-5; \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue48.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue48.js new file mode 100644 index 00000000..031e85b3 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue48.js @@ -0,0 +1 @@ +var s, i; s = ''; i = 0; \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue50.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue50.js new file mode 100644 index 00000000..060f9df8 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue50.js @@ -0,0 +1,9 @@ +function bar(a) { + try { + foo(); + } catch(e) { + alert("Exception caught (foo not defined)"); + } + alert(a); // 10 in FF, "[object Error]" in IE +} +bar(10); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue53.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue53.js new file mode 100644 index 00000000..4f8b32f1 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue53.js @@ -0,0 +1 @@ +x = (y, z) diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue54.1.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue54.1.js new file mode 100644 index 00000000..967052e8 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue54.1.js @@ -0,0 +1,3 @@ +foo.toString(); +a.toString(16); +b.toString.call(c); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue68.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue68.js new file mode 100644 index 00000000..14054d01 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue68.js @@ -0,0 +1,5 @@ +function f() { + if (a) return; + g(); + function g(){} +}; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue69.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue69.js new file mode 100644 index 00000000..d25ecd67 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue69.js @@ -0,0 +1 @@ +[(a,b)] diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue9.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue9.js new file mode 100644 index 00000000..61588614 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue9.js @@ -0,0 +1,4 @@ +var a = { + a: 1, + b: 2, // <-- trailing comma +}; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/mangle.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/mangle.js new file mode 100644 index 00000000..c271a26d --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/mangle.js @@ -0,0 +1,5 @@ +(function() { + var x = function fun(a, fun, b) { + return fun; + }; +}()); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/null_string.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/null_string.js new file mode 100644 index 00000000..a675b1c5 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/null_string.js @@ -0,0 +1 @@ +var nullString = "\0" \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/strict-equals.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/strict-equals.js new file mode 100644 index 00000000..b631f4c3 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/strict-equals.js @@ -0,0 +1,3 @@ +typeof a === 'string' +b + "" !== c + "" +d < e === f < g diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/var.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/var.js new file mode 100644 index 00000000..609a35d2 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/var.js @@ -0,0 +1,3 @@ +// var declarations after each other should be combined +var a = 1; +var b = 2; \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/whitespace.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/whitespace.js new file mode 100644 index 00000000..6a15c464 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/whitespace.js @@ -0,0 +1,21 @@ +function id(a) { + // Form-Feed + // Vertical Tab + // No-Break Space + ᠎// Mongolian Vowel Separator +  // En quad +  // Em quad +  // En space +  // Em space +  // Three-Per-Em Space +  // Four-Per-Em Space +  // Six-Per-Em Space +  // Figure Space +  // Punctuation Space +  // Thin Space +  // Hair Space +  // Narrow No-Break Space +  // Medium Mathematical Space +  // Ideographic Space + return a; +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/with.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/with.js new file mode 100644 index 00000000..de266ed5 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/with.js @@ -0,0 +1,2 @@ +with({}) { +}; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/scripts.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/scripts.js new file mode 100644 index 00000000..5d334ff7 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/scripts.js @@ -0,0 +1,55 @@ +var fs = require('fs'), + uglify = require('../../uglify-js'), + jsp = uglify.parser, + nodeunit = require('nodeunit'), + path = require('path'), + pro = uglify.uglify; + +var Script = process.binding('evals').Script; + +var scriptsPath = __dirname; + +function compress(code) { + var ast = jsp.parse(code); + ast = pro.ast_mangle(ast); + ast = pro.ast_squeeze(ast, { no_warnings: true }); + ast = pro.ast_squeeze_more(ast); + return pro.gen_code(ast); +}; + +var testDir = path.join(scriptsPath, "compress", "test"); +var expectedDir = path.join(scriptsPath, "compress", "expected"); + +function getTester(script) { + return function(test) { + var testPath = path.join(testDir, script); + var expectedPath = path.join(expectedDir, script); + var content = fs.readFileSync(testPath, 'utf-8'); + var outputCompress = compress(content); + + // Check if the noncompressdata is larger or same size as the compressed data + test.ok(content.length >= outputCompress.length); + + // Check that a recompress gives the same result + var outputReCompress = compress(content); + test.equal(outputCompress, outputReCompress); + + // Check if the compressed output is what is expected + var expected = fs.readFileSync(expectedPath, 'utf-8'); + test.equal(outputCompress, expected.replace(/(\r?\n)+$/, "")); + + test.done(); + }; +}; + +var tests = {}; + +var scripts = fs.readdirSync(testDir); +for (var i in scripts) { + var script = scripts[i]; + if (/\.js$/.test(script)) { + tests[script] = getTester(script); + } +} + +module.exports = nodeunit.testCase(tests); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/269.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/269.js new file mode 100644 index 00000000..256ad1c9 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/269.js @@ -0,0 +1,13 @@ +var jsp = require("uglify-js").parser; +var pro = require("uglify-js").uglify; + +var test_code = "var JSON;JSON||(JSON={});"; + +var ast = jsp.parse(test_code, false, false); +var nonembed_token_code = pro.gen_code(ast); +ast = jsp.parse(test_code, false, true); +var embed_token_code = pro.gen_code(ast); + +console.log("original: " + test_code); +console.log("no token: " + nonembed_token_code); +console.log(" token: " + embed_token_code); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/app.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/app.js new file mode 100644 index 00000000..2c6257eb --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/app.js @@ -0,0 +1,22315 @@ +/* Modernizr 2.0.6 (Custom Build) | MIT & BSD + * Build: http://www.modernizr.com/download/#-iepp + */ +;window.Modernizr=function(a,b,c){function w(a,b){return!!~(""+a).indexOf(b)}function v(a,b){return typeof a===b}function u(a,b){return t(prefixes.join(a+";")+(b||""))}function t(a){j.cssText=a}var d="2.0.6",e={},f=b.documentElement,g=b.head||b.getElementsByTagName("head")[0],h="modernizr",i=b.createElement(h),j=i.style,k,l=Object.prototype.toString,m={},n={},o={},p=[],q,r={}.hasOwnProperty,s;!v(r,c)&&!v(r.call,c)?s=function(a,b){return r.call(a,b)}:s=function(a,b){return b in a&&v(a.constructor.prototype[b],c)};for(var x in m)s(m,x)&&(q=x.toLowerCase(),e[q]=m[x](),p.push((e[q]?"":"no-")+q));t(""),i=k=null,a.attachEvent&&function(){var a=b.createElement("div");a.innerHTML="";return a.childNodes.length!==1}()&&function(a,b){function s(a){var b=-1;while(++b to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Check for digits + rdigit = /\d/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return (context || rootjQuery).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.6.3", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.done( fn ); + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).unbind( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery._Deferred(); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNaN: function( obj ) { + return obj == null || !rdigit.test( obj ) || isNaN( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return (new Function( "return " + data ))(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + if ( !array ) { + return -1; + } + + if ( indexOf ) { + return indexOf.call( array, elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return (new Date()).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +var // Promise methods + promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), + // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + // Create a simple deferred (one callbacks list) + _Deferred: function() { + var // callbacks list + callbacks = [], + // stored [ context , args ] + fired, + // to avoid firing when already doing so + firing, + // flag to know if the deferred has been cancelled + cancelled, + // the deferred itself + deferred = { + + // done( f1, f2, ...) + done: function() { + if ( !cancelled ) { + var args = arguments, + i, + length, + elem, + type, + _fired; + if ( fired ) { + _fired = fired; + fired = 0; + } + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + deferred.done.apply( deferred, elem ); + } else if ( type === "function" ) { + callbacks.push( elem ); + } + } + if ( _fired ) { + deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); + } + } + return this; + }, + + // resolve with given context and args + resolveWith: function( context, args ) { + if ( !cancelled && !fired && !firing ) { + // make sure args are available (#8421) + args = args || []; + firing = 1; + try { + while( callbacks[ 0 ] ) { + callbacks.shift().apply( context, args ); + } + } + finally { + fired = [ context, args ]; + firing = 0; + } + } + return this; + }, + + // resolve with this as context and given arguments + resolve: function() { + deferred.resolveWith( this, arguments ); + return this; + }, + + // Has this deferred been resolved? + isResolved: function() { + return !!( firing || fired ); + }, + + // Cancel + cancel: function() { + cancelled = 1; + callbacks = []; + return this; + } + }; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + Deferred: function( func ) { + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + // Add errorDeferred methods, then and promise + jQuery.extend( deferred, { + then: function( doneCallbacks, failCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ); + return this; + }, + always: function() { + return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); + }, + fail: failDeferred.done, + rejectWith: failDeferred.resolveWith, + reject: failDeferred.resolve, + isRejected: failDeferred.isResolved, + pipe: function( fnDone, fnFail ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + if ( promise ) { + return promise; + } + promise = obj = {}; + } + var i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; + } + return obj; + } + }); + // Make sure only one callback list will be used + deferred.done( failDeferred.cancel ).fail( deferred.cancel ); + // Unexpose cancel + delete deferred.cancel; + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = arguments, + i = 0, + length = args.length, + count = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + // Strange bug in FF4: + // Values changed onto the arguments object sometimes end up as undefined values + // outside the $.when method. Cloning the object into a fresh array solves the issue + deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) ); + } + }; + } + if ( length > 1 ) { + for( ; i < length; i++ ) { + if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return deferred.promise(); + } +}); + + + +jQuery.support = (function() { + + var div = document.createElement( "div" ), + documentElement = document.documentElement, + all, + a, + select, + opt, + input, + marginDiv, + support, + fragment, + body, + testElementParent, + testElement, + testElementStyle, + tds, + events, + eventName, + i, + isSupported; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
a"; + + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName( "tbody" ).length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName( "link" ).length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains it's value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + div.innerHTML = ""; + + // Figure out if the W3C box model works as expected + div.style.width = div.style.paddingLeft = "1px"; + + body = document.getElementsByTagName( "body" )[ 0 ]; + // We use our own, invisible, body unless the body is already present + // in which case we use a div (#9239) + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + jQuery.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + support.boxModel = div.offsetWidth === 2; + + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } + + div.innerHTML = "
t
"; + tds = div.getElementsByTagName( "td" ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + div.innerHTML = ""; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( document.defaultView && document.defaultView.getComputedStyle ) { + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + // Remove the body element we added + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for( i in { + submit: 1, + change: 1, + focusin: 1 + } ) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + // Null connected elements to avoid leaks in IE + testElement = fragment = select = opt = body = marginDiv = div = input = null; + + return support; +})(); + +// Keep track of boxModel +jQuery.boxModel = jQuery.support.boxModel; + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([a-z])([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || (pvt && id && (cache[ id ] && !cache[ id ][ internalKey ]))) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ jQuery.expando ] = id = ++jQuery.uuid; + } else { + id = jQuery.expando; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + } else { + cache[ id ] = jQuery.extend(cache[ id ], name); + } + } + + thisCache = cache[ id ]; + + // Internal jQuery data is stored in a separate object inside the object's data + // cache in order to avoid key collisions between internal data and user-defined + // data + if ( pvt ) { + if ( !thisCache[ internalKey ] ) { + thisCache[ internalKey ] = {}; + } + + thisCache = thisCache[ internalKey ]; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should + // not attempt to inspect the internal events object using jQuery.data, as this + // internal data object is undocumented and subject to change. + if ( name === "events" && !thisCache[name] ) { + return thisCache[ internalKey ] && thisCache[ internalKey ].events; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + if ( thisCache ) { + + // Support interoperable removal of hyphenated or camelcased keys + if ( !thisCache[ name ] ) { + name = jQuery.camelCase( name ); + } + + delete thisCache[ name ]; + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !isEmptyDataObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( pvt ) { + delete cache[ id ][ internalKey ]; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + var internalCache = cache[ id ][ internalKey ]; + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the entire user cache at once because it's faster than + // iterating through each key, but we need to continue to persist internal + // data if it existed + if ( internalCache ) { + cache[ id ] = {}; + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + + cache[ id ][ internalKey ] = internalCache; + + // Otherwise, we need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + } else if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } else { + elem[ jQuery.expando ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 ) { + var attr = this[0].attributes, name; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( this[0], name, data[ name ] ); + } + } + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var $this = jQuery( this ), + args = [ parts[0], value ]; + + $this.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + $this.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + !jQuery.isNaN( data ) ? parseFloat( data ) : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON +// property to be considered empty objects; this property always exists in +// order to make sure JSON.stringify does not expose internal metadata +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery.data( elem, deferDataKey, undefined, true ); + if ( defer && + ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && + ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery.data( elem, queueDataKey, undefined, true ) && + !jQuery.data( elem, markDataKey, undefined, true ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.resolve(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = (type || "fx") + "mark"; + jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); + if ( count ) { + jQuery.data( elem, key, count, true ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + if ( elem ) { + type = (type || "fx") + "queue"; + var q = jQuery.data( elem, type, undefined, true ); + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery.data( elem, type, jQuery.makeArray(data), true ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + defer; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { + count++; + tmp.done( resolve ); + } + } + resolve(); + return defer.promise(); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + nodeHook, boolHook; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = (value || "").split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return undefined; + } + + var isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attrFix: { + // Always normalize to ensure hook usage + tabindex: "tabIndex" + }, + + attr: function( elem, name, value, pass ) { + var nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( !("getAttribute" in elem) ) { + return jQuery.prop( elem, name, value ); + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // Normalize the name if needed + if ( notxml ) { + name = jQuery.attrFix[ name ] || name; + + hooks = jQuery.attrHooks[ name ]; + + if ( !hooks ) { + // Use boolHook for boolean attributes + if ( rboolean.test( name ) ) { + hooks = boolHook; + + // Use nodeHook if available( IE6/7 ) + } else if ( nodeHook ) { + hooks = nodeHook; + } + } + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return undefined; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, name ) { + var propName; + if ( elem.nodeType === 1 ) { + name = jQuery.attrFix[ name ] || name; + + jQuery.attr( elem, name, "" ); + elem.removeAttribute( name ); + + // Set corresponding property to false for boolean attributes + if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { + elem[ propName ] = false; + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return (elem[ name ] = value); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabindex propHook to attrHooks for back-compat +jQuery.attrHooks.tabIndex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode; + return jQuery.prop( elem, name ) === true || ( attrNode = elem.getAttributeNode( name ) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !jQuery.support.getSetAttribute ) { + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + // Return undefined if nodeValue is empty string + return ret && ret.nodeValue !== "" ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return (ret.nodeValue = value + ""); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return (elem.style.cssText = "" + value); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); + } + } + }); +}); + + + + +var rnamespaces = /\.(.*)$/, + rformElems = /^(?:textarea|input|select)$/i, + rperiod = /\./g, + rspaces = / /g, + rescape = /[^\w\s.|`]/g, + fcleanup = function( nm ) { + return nm.replace(rescape, "\\$&"); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } else if ( !handler ) { + // Fixes bug #7229. Fix recommended by jdalton + return; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery._data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events, + eventHandle = elemData.handle; + + if ( !events ) { + elemData.events = events = {}; + } + + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + if ( !handleObj.guid ) { + handleObj.guid = handler.guid; + } + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // Only use addEventListener/attachEvent if the special + // events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } + + var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem, undefined, true ); + } + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Event object or event type + var type = event.type || event, + namespaces = [], + exclusive; + + if ( type.indexOf("!") >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.exclusive = exclusive; + event.namespace = namespaces.join("."); + event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); + + // triggerHandler() and global events don't bubble or run the default action + if ( onlyHandlers || !elem ) { + event.preventDefault(); + event.stopPropagation(); + } + + // Handle a global trigger + if ( !elem ) { + // TODO: Stop taunting the data cache; remove global events and always attach to document + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); + return; + } + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + event.target = elem; + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + var cur = elem, + // IE doesn't like method names with a colon (#3533, #8272) + ontype = type.indexOf(":") < 0 ? "on" + type : ""; + + // Fire event on the current element, then bubble up the DOM tree + do { + var handle = jQuery._data( cur, "handle" ); + + event.currentTarget = cur; + if ( handle ) { + handle.apply( cur, data ); + } + + // Trigger an inline bound script + if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { + event.result = false; + event.preventDefault(); + } + + // Bubble up to document, then to window + cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; + } while ( cur && !event.isPropagationStopped() ); + + // If nobody prevented the default action, do it now + if ( !event.isDefaultPrevented() ) { + var old, + special = jQuery.event.special[ type ] || {}; + + if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction)() check here because IE6/7 fails that test. + // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. + try { + if ( ontype && elem[ type ] ) { + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + jQuery.event.triggered = type; + elem[ type ](); + } + } catch ( ieError ) {} + + if ( old ) { + elem[ ontype ] = old; + } + + jQuery.event.triggered = undefined; + } + } + + return event.result; + }, + + handle: function( event ) { + event = jQuery.event.fix( event || window.event ); + // Snapshot the handlers list since a called handler may add/remove events. + var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), + run_all = !event.exclusive && !event.namespace, + args = Array.prototype.slice.call( arguments, 0 ); + + // Use the fix-ed Event rather than the (read-only) native event + args[0] = event; + event.currentTarget = this; + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Triggered event must 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event. + if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + // Fixes #1925 where srcElement might not be defined either + event.target = event.srcElement || document; + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var eventDocument = event.target.ownerDocument || document, + doc = eventDocument.documentElement, + body = eventDocument.body; + + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { + event.which = event.charCode != null ? event.charCode : event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, + liveConvert( handleObj.origType, handleObj.selector ), + jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); + }, + + remove: function( handleObj ) { + jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); + } + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + + // Check if mouse(over|out) are still within the same parent element + var related = event.relatedTarget, + inside = false, + eventType = event.type; + + event.type = event.data; + + if ( related !== this ) { + + if ( related ) { + inside = jQuery.contains( this, related ); + } + + if ( !inside ) { + + jQuery.event.handle.apply( this, arguments ); + + event.type = eventType; + } + } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( !jQuery.nodeName( this, "form" ) ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, + type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, + type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var changeFilters, + + getVal = function( elem ) { + var type = jQuery.nodeName( elem, "input" ) ? elem.type : "", + val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( jQuery.nodeName( elem, "select" ) ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery._data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery._data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + e.liveFired = undefined; + jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + beforedeactivate: testChange, + + click: function( e ) { + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { + testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information + beforeactivate: function( e ) { + var elem = e.target; + jQuery._data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return rformElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return rformElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; + + // Handle when the input is .focus()'d + changeFilters.focus = changeFilters.beforeactivate; +} + +function trigger( type, elem, args ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + // Don't pass args or remember liveFired; they apply to the donor event. + var event = jQuery.extend( {}, args[ 0 ] ); + event.type = type; + event.originalEvent = {}; + event.liveFired = undefined; + jQuery.event.handle.call( elem, event ); + if ( event.isDefaultPrevented() ) { + args[ 0 ].preventDefault(); + } +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + + function handler( donor ) { + // Donor event is always a native one; fix it and switch its type. + // Let focusin/out handler cancel the donor focus/blur event. + var e = jQuery.event.fix( donor ); + e.type = fix; + e.originalEvent = {}; + jQuery.event.trigger( e, null, e.target ); + if ( e.isDefaultPrevented() ) { + donor.preventDefault(); + } + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + var handler; + + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( arguments.length === 2 || data === false ) { + fn = data; + data = undefined; + } + + if ( name === "one" ) { + handler = function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }; + handler.guid = fn.guid || jQuery.guid++; + } else { + handler = fn; + } + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( typeof types === "object" && !types.preventDefault ) { + for ( var key in types ) { + context[ name ]( key, data, types[key], selector ); + } + + return this; + } + + if ( name === "die" && !types && + origSelector && origSelector.charAt(0) === "." ) { + + context.unbind( origSelector ); + + return this; + } + + if ( data === false || jQuery.isFunction( data ) ) { + fn = data || returnFalse; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( liveMap[ type ] ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + for ( var j = 0, l = context.length; j < l; j++ ) { + jQuery.event.add( context[j], "live." + liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + } + + } else { + // unbind live handler + context.unbind( "live." + liveConvert( type, selector ), fn ); + } + } + + return this; + }; +}); + +function liveHandler( event ) { + var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + elems = [], + selectors = [], + events = jQuery._data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) + if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { + return; + } + + if ( event.namespace ) { + namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + close = match[i]; + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { + elem = close.elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + event.type = handleObj.preType; + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + + // Make sure not to accidentally match a child element with the same selector + if ( related && jQuery.contains( elem, related ) ) { + related = elem; + } + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj, level: close.level }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + + if ( maxLevel && match.level > maxLevel ) { + break; + } + + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + ret = match.handleObj.origHandler.apply( match.elem, arguments ); + + if ( ret === false || event.isPropagationStopped() ) { + maxLevel = match.level; + + if ( ret === false ) { + stop = false; + } + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); +} + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.bind( name, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var match, + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var found, item, + filter = Expr.filter[ type ], + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw "Syntax error, unrecognized expression: " + msg; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + var first = match[2], + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +Sizzle.getText = function( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += Sizzle.getText( elem.childNodes ); + } + } + + return ret; +}; + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( typeof selector === "string" ? + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array + if ( jQuery.isArray( selectors ) ) { + var match, selector, + matches = {}, + level = 1; + + if ( cur && selectors.length ) { + for ( i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[ selector ] ) { + matches[ selector ] = POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[ selector ]; + + if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { + ret.push({ selector: selector, elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ), + // The variable 'args' was introduced in + // https://github.com/jquery/jquery/commit/52a0238 + // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. + // http://code.google.com/p/v8/issues/detail?id=1050 + args = slice.call(arguments); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, args.join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +} + + + + +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /
", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + */ + +(function() { + this.loggly = function(opts) { + this.user_agent = get_agent(); + this.browser_size = get_size(); + log_methods = {'error': 5, 'warn': 4, 'info': 3, 'debug': 2, 'log': 1}; + if (!opts.url) throw new Error("Please include a Loggly HTTP URL."); + if (!opts.level) { + this.level = log_methods['info']; + } else { + this.level = log_methods[opts.level]; + } + this.log = function(data) { + if (log_methods['log'] == this.level) { + opts.data = data; + janky(opts); + } + }; + this.debug = function(data) { + if (log_methods['debug'] >= this.level) { + opts.data = data; + janky(opts); + } + }; + this.info = function(data) { + if (log_methods['info'] >= this.level) { + opts.data = data; + janky(opts); + } + }; + this.warn = function(data) { + if (log_methods['warn'] >= this.level) { + opts.data = data; + janky(opts); + } + }; + this.error = function(data) { + if (log_methods['error'] >= this.level) { + opts.data = data; + janky(opts); + } + }; + }; + this.janky = function(opts) { + janky._form(function(iframe, form) { + form.setAttribute("action", opts.url); + form.setAttribute("method", "post"); + janky._input(iframe, form, opts.data); + form.submit(); + setTimeout(function(){ + document.body.removeChild(iframe); + }, 2000); + }); + }; + this.janky._form = function(cb) { + var iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + iframe.style.display = "none"; + setTimeout(function() { + var form = iframe.contentWindow.document.createElement("form"); + iframe.contentWindow.document.body.appendChild(form); + cb(iframe, form); + }, 0); + }; + this.janky._input = function(iframe, form, data) { + var inp = iframe.contentWindow.document.createElement("input"); + inp.setAttribute("type", "hidden"); + inp.setAttribute("name", "source"); + inp.value = "castor " + data; + form.appendChild(inp); + }; + this.get_agent = function () { + return navigator.appCodeName + navigator.appName + navigator.appVersion; + }; + this.get_size = function () { + var width = 0; var height = 0; + if( typeof( window.innerWidth ) == 'number' ) { + width = window.innerWidth; height = window.innerHeight; + } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) { + width = document.documentElement.clientWidth; height = document.documentElement.clientHeight; + } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) { + width = document.body.clientWidth; height = document.body.clientHeight; + } + return {'height': height, 'width': width}; + }; +})(); + + +jsworld={};jsworld.formatIsoDateTime=function(a,b){if(typeof a==="undefined")a=new Date;if(typeof b==="undefined")b=false;var c=jsworld.formatIsoDate(a)+" "+jsworld.formatIsoTime(a);if(b){var d=a.getHours()-a.getUTCHours();var e=Math.abs(d);var f=a.getUTCMinutes();var g=a.getMinutes();if(g!=f&&f<30&&d<0)e--;if(g!=f&&f>30&&d>0)e--;var h;if(g!=f)h=":30";else h=":00";var i;if(e<10)i="0"+e+h;else i=""+e+h;if(d<0)i="-"+i;else i="+"+i;c=c+i}return c};jsworld.formatIsoDate=function(a){if(typeof a==="undefined")a=new Date;var b=a.getFullYear();var c=a.getMonth()+1;var d=a.getDate();return b+"-"+jsworld._zeroPad(c,2)+"-"+jsworld._zeroPad(d,2)};jsworld.formatIsoTime=function(a){if(typeof a==="undefined")a=new Date;var b=a.getHours();var c=a.getMinutes();var d=a.getSeconds();return jsworld._zeroPad(b,2)+":"+jsworld._zeroPad(c,2)+":"+jsworld._zeroPad(d,2)};jsworld.parseIsoDateTime=function(a){if(typeof a!="string")throw"Error: The parameter must be a string";var b=a.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d)/);if(b===null)b=a.match(/^(\d\d\d\d)(\d\d)(\d\d)[T ](\d\d)(\d\d)(\d\d)/);if(b===null)b=a.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d)(\d\d)(\d\d)/);if(b===null)b=a.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d)/);if(b===null)throw"Error: Invalid ISO-8601 date/time string";var c=parseInt(b[1],10);var d=parseInt(b[2],10);var e=parseInt(b[3],10);var f=parseInt(b[4],10);var g=parseInt(b[5],10);var h=parseInt(b[6],10);if(d<1||d>12||e<1||e>31||f<0||f>23||g<0||g>59||h<0||h>59)throw"Error: Invalid ISO-8601 date/time value";var i=new Date(c,d-1,e,f,g,h);if(i.getDate()!=e||i.getMonth()+1!=d)throw"Error: Invalid date";return i};jsworld.parseIsoDate=function(a){if(typeof a!="string")throw"Error: The parameter must be a string";var b=a.match(/^(\d\d\d\d)-(\d\d)-(\d\d)/);if(b===null)b=a.match(/^(\d\d\d\d)(\d\d)(\d\d)/);if(b===null)throw"Error: Invalid ISO-8601 date string";var c=parseInt(b[1],10);var d=parseInt(b[2],10);var e=parseInt(b[3],10);if(d<1||d>12||e<1||e>31)throw"Error: Invalid ISO-8601 date value";var f=new Date(c,d-1,e);if(f.getDate()!=e||f.getMonth()+1!=d)throw"Error: Invalid date";return f};jsworld.parseIsoTime=function(a){if(typeof a!="string")throw"Error: The parameter must be a string";var b=a.match(/^(\d\d):(\d\d):(\d\d)/);if(b===null)b=a.match(/^(\d\d)(\d\d)(\d\d)/);if(b===null)throw"Error: Invalid ISO-8601 date/time string";var c=parseInt(b[1],10);var d=parseInt(b[2],10);var e=parseInt(b[3],10);if(c<0||c>23||d<0||d>59||e<0||e>59)throw"Error: Invalid ISO-8601 time value";return new Date(0,0,0,c,d,e)};jsworld._trim=function(a){var b=" \n\r\t\f \u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000";for(var c=0;c=0;c--){if(b.indexOf(a.charAt(c))===-1){a=a.substring(0,c+1);break}}return b.indexOf(a.charAt(0))===-1?a:""};jsworld._isNumber=function(a){if(typeof a=="number")return true;if(typeof a!="string")return false;var b=a+"";return/^-?(\d+|\d*\.\d+)$/.test(b)};jsworld._isInteger=function(a){if(typeof a!="number"&&typeof a!="string")return false;var b=a+"";return/^-?\d+$/.test(b)};jsworld._isFloat=function(a){if(typeof a!="number"&&typeof a!="string")return false;var b=a+"";return/^-?\.\d+?$/.test(b)};jsworld._hasOption=function(a,b){if(typeof a!="string"||typeof b!="string")return false;if(b.indexOf(a)!=-1)return true;else return false};jsworld._stringReplaceAll=function(a,b,c){var d;if(b.length==1&&c.length==1){d="";for(var e=0;e0){if(d.length>0)g=parseInt(d.shift(),10);if(isNaN(g))throw"Error: Invalid grouping";if(g==-1){e=a.substring(0,f)+e;break}f-=g;if(f<1){e=a.substring(0,f+g)+e;break}e=c+a.substring(f,f+g)+e}return e};jsworld._formatFractionPart=function(a,b){for(var c=0;a.length0)return a;else throw"Empty or no string"};if(a==null||typeof a!="object")throw"Error: Invalid/missing locale properties";if(typeof a.decimal_point!="string")throw"Error: Invalid/missing decimal_point property";this.decimal_point=a.decimal_point;if(typeof a.thousands_sep!="string")throw"Error: Invalid/missing thousands_sep property";this.thousands_sep=a.thousands_sep;if(typeof a.grouping!="string")throw"Error: Invalid/missing grouping property";this.grouping=a.grouping;if(typeof a.int_curr_symbol!="string")throw"Error: Invalid/missing int_curr_symbol property";if(!/[A-Za-z]{3}.?/.test(a.int_curr_symbol))throw"Error: Invalid int_curr_symbol property";this.int_curr_symbol=a.int_curr_symbol;if(typeof a.currency_symbol!="string")throw"Error: Invalid/missing currency_symbol property";this.currency_symbol=a.currency_symbol;if(typeof a.frac_digits!="number"&&a.frac_digits<0)throw"Error: Invalid/missing frac_digits property";this.frac_digits=a.frac_digits;if(a.mon_decimal_point===null||a.mon_decimal_point==""){if(this.frac_digits>0)throw"Error: Undefined mon_decimal_point property";else a.mon_decimal_point=""}if(typeof a.mon_decimal_point!="string")throw"Error: Invalid/missing mon_decimal_point property";this.mon_decimal_point=a.mon_decimal_point;if(typeof a.mon_thousands_sep!="string")throw"Error: Invalid/missing mon_thousands_sep property";this.mon_thousands_sep=a.mon_thousands_sep;if(typeof a.mon_grouping!="string")throw"Error: Invalid/missing mon_grouping property";this.mon_grouping=a.mon_grouping;if(typeof a.positive_sign!="string")throw"Error: Invalid/missing positive_sign property";this.positive_sign=a.positive_sign;if(typeof a.negative_sign!="string")throw"Error: Invalid/missing negative_sign property";this.negative_sign=a.negative_sign;if(a.p_cs_precedes!==0&&a.p_cs_precedes!==1)throw"Error: Invalid/missing p_cs_precedes property, must be 0 or 1";this.p_cs_precedes=a.p_cs_precedes;if(a.n_cs_precedes!==0&&a.n_cs_precedes!==1)throw"Error: Invalid/missing n_cs_precedes, must be 0 or 1";this.n_cs_precedes=a.n_cs_precedes;if(a.p_sep_by_space!==0&&a.p_sep_by_space!==1&&a.p_sep_by_space!==2)throw"Error: Invalid/missing p_sep_by_space property, must be 0, 1 or 2";this.p_sep_by_space=a.p_sep_by_space;if(a.n_sep_by_space!==0&&a.n_sep_by_space!==1&&a.n_sep_by_space!==2)throw"Error: Invalid/missing n_sep_by_space property, must be 0, 1, or 2";this.n_sep_by_space=a.n_sep_by_space;if(a.p_sign_posn!==0&&a.p_sign_posn!==1&&a.p_sign_posn!==2&&a.p_sign_posn!==3&&a.p_sign_posn!==4)throw"Error: Invalid/missing p_sign_posn property, must be 0, 1, 2, 3 or 4";this.p_sign_posn=a.p_sign_posn;if(a.n_sign_posn!==0&&a.n_sign_posn!==1&&a.n_sign_posn!==2&&a.n_sign_posn!==3&&a.n_sign_posn!==4)throw"Error: Invalid/missing n_sign_posn property, must be 0, 1, 2, 3 or 4";this.n_sign_posn=a.n_sign_posn;if(typeof a.int_frac_digits!="number"&&a.int_frac_digits<0)throw"Error: Invalid/missing int_frac_digits property";this.int_frac_digits=a.int_frac_digits;if(a.int_p_cs_precedes!==0&&a.int_p_cs_precedes!==1)throw"Error: Invalid/missing int_p_cs_precedes property, must be 0 or 1";this.int_p_cs_precedes=a.int_p_cs_precedes;if(a.int_n_cs_precedes!==0&&a.int_n_cs_precedes!==1)throw"Error: Invalid/missing int_n_cs_precedes property, must be 0 or 1";this.int_n_cs_precedes=a.int_n_cs_precedes;if(a.int_p_sep_by_space!==0&&a.int_p_sep_by_space!==1&&a.int_p_sep_by_space!==2)throw"Error: Invalid/missing int_p_sep_by_spacev, must be 0, 1 or 2";this.int_p_sep_by_space=a.int_p_sep_by_space;if(a.int_n_sep_by_space!==0&&a.int_n_sep_by_space!==1&&a.int_n_sep_by_space!==2)throw"Error: Invalid/missing int_n_sep_by_space property, must be 0, 1, or 2";this.int_n_sep_by_space=a.int_n_sep_by_space;if(a.int_p_sign_posn!==0&&a.int_p_sign_posn!==1&&a.int_p_sign_posn!==2&&a.int_p_sign_posn!==3&&a.int_p_sign_posn!==4)throw"Error: Invalid/missing int_p_sign_posn property, must be 0, 1, 2, 3 or 4";this.int_p_sign_posn=a.int_p_sign_posn;if(a.int_n_sign_posn!==0&&a.int_n_sign_posn!==1&&a.int_n_sign_posn!==2&&a.int_n_sign_posn!==3&&a.int_n_sign_posn!==4)throw"Error: Invalid/missing int_n_sign_posn property, must be 0, 1, 2, 3 or 4";this.int_n_sign_posn=a.int_n_sign_posn;if(a==null||typeof a!="object")throw"Error: Invalid/missing time locale properties";try{this.abday=this._parseList(a.abday,7)}catch(b){throw"Error: Invalid abday property: "+b}try{this.day=this._parseList(a.day,7)}catch(b){throw"Error: Invalid day property: "+b}try{this.abmon=this._parseList(a.abmon,12)}catch(b){throw"Error: Invalid abmon property: "+b}try{this.mon=this._parseList(a.mon,12)}catch(b){throw"Error: Invalid mon property: "+b}try{this.d_fmt=this._validateFormatString(a.d_fmt)}catch(b){throw"Error: Invalid d_fmt property: "+b}try{this.t_fmt=this._validateFormatString(a.t_fmt)}catch(b){throw"Error: Invalid t_fmt property: "+b}try{this.d_t_fmt=this._validateFormatString(a.d_t_fmt)}catch(b){throw"Error: Invalid d_t_fmt property: "+b}try{var c=this._parseList(a.am_pm,2);this.am=c[0];this.pm=c[1]}catch(b){this.am="";this.pm=""}this.getAbbreviatedWeekdayName=function(a){if(typeof a=="undefined"||a===null)return this.abday;if(!jsworld._isInteger(a)||a<0||a>6)throw"Error: Invalid weekday argument, must be an integer [0..6]";return this.abday[a]};this.getWeekdayName=function(a){if(typeof a=="undefined"||a===null)return this.day;if(!jsworld._isInteger(a)||a<0||a>6)throw"Error: Invalid weekday argument, must be an integer [0..6]";return this.day[a]};this.getAbbreviatedMonthName=function(a){if(typeof a=="undefined"||a===null)return this.abmon;if(!jsworld._isInteger(a)||a<0||a>11)throw"Error: Invalid month argument, must be an integer [0..11]";return this.abmon[a]};this.getMonthName=function(a){if(typeof a=="undefined"||a===null)return this.mon;if(!jsworld._isInteger(a)||a<0||a>11)throw"Error: Invalid month argument, must be an integer [0..11]";return this.mon[a]};this.getDecimalPoint=function(){return this.decimal_point};this.getCurrencySymbol=function(){return this.currency_symbol};this.getIntCurrencySymbol=function(){return this.int_curr_symbol.substring(0,3)};this.currencySymbolPrecedes=function(){if(this.p_cs_precedes==1)return true;else return false};this.intCurrencySymbolPrecedes=function(){if(this.int_p_cs_precedes==1)return true;else return false};this.getMonetaryDecimalPoint=function(){return this.mon_decimal_point};this.getFractionalDigits=function(){return this.frac_digits};this.getIntFractionalDigits=function(){return this.int_frac_digits}};jsworld.NumericFormatter=function(a){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance";this.lc=a;this.format=function(a,b){if(typeof a=="string")a=jsworld._trim(a);if(!jsworld._isNumber(a))throw"Error: The input is not a number";var c=parseFloat(a,10);var d=jsworld._getPrecision(b);if(d!=-1)c=Math.round(c*Math.pow(10,d))/Math.pow(10,d);var e=jsworld._splitNumber(String(c));var f;if(c===0)f="0";else f=jsworld._hasOption("^",b)?e.integer:jsworld._formatIntegerPart(e.integer,this.lc.grouping,this.lc.thousands_sep);var g=d!=-1?jsworld._formatFractionPart(e.fraction,d):e.fraction;var h=g.length?f+this.lc.decimal_point+g:f;if(jsworld._hasOption("~",b)||c===0){return h}else{if(jsworld._hasOption("+",b)||c<0){if(c>0)return"+"+h;else if(c<0)return"-"+h;else return h}else{return h}}}};jsworld.DateTimeFormatter=function(a){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance.";this.lc=a;this.formatDate=function(a){var b=null;if(typeof a=="string"){try{b=jsworld.parseIsoDate(a)}catch(c){b=jsworld.parseIsoDateTime(a)}}else if(a!==null&&typeof a=="object"){b=a}else{throw"Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"}return this._applyFormatting(b,this.lc.d_fmt)};this.formatTime=function(a){var b=null;if(typeof a=="string"){try{b=jsworld.parseIsoTime(a)}catch(c){b=jsworld.parseIsoDateTime(a)}}else if(a!==null&&typeof a=="object"){b=a}else{throw"Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"}return this._applyFormatting(b,this.lc.t_fmt)};this.formatDateTime=function(a){var b=null;if(typeof a=="string"){b=jsworld.parseIsoDateTime(a)}else if(a!==null&&typeof a=="object"){b=a}else{throw"Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"}return this._applyFormatting(b,this.lc.d_t_fmt)};this._applyFormatting=function(a,b){b=b.replace(/%%/g,"%");b=b.replace(/%a/g,this.lc.abday[a.getDay()]);b=b.replace(/%A/g,this.lc.day[a.getDay()]);b=b.replace(/%b/g,this.lc.abmon[a.getMonth()]);b=b.replace(/%B/g,this.lc.mon[a.getMonth()]);b=b.replace(/%d/g,jsworld._zeroPad(a.getDate(),2));b=b.replace(/%e/g,jsworld._spacePad(a.getDate(),2));b=b.replace(/%F/g,a.getFullYear()+"-"+jsworld._zeroPad(a.getMonth()+1,2)+"-"+jsworld._zeroPad(a.getDate(),2));b=b.replace(/%h/g,this.lc.abmon[a.getMonth()]);b=b.replace(/%H/g,jsworld._zeroPad(a.getHours(),2));b=b.replace(/%I/g,jsworld._zeroPad(this._hours12(a.getHours()),2));b=b.replace(/%k/g,a.getHours());b=b.replace(/%l/g,this._hours12(a.getHours()));b=b.replace(/%m/g,jsworld._zeroPad(a.getMonth()+1,2));b=b.replace(/%n/g,"\n");b=b.replace(/%M/g,jsworld._zeroPad(a.getMinutes(),2));b=b.replace(/%p/g,this._getAmPm(a.getHours()));b=b.replace(/%P/g,this._getAmPm(a.getHours()).toLocaleLowerCase());b=b.replace(/%R/g,jsworld._zeroPad(a.getHours(),2)+":"+jsworld._zeroPad(a.getMinutes(),2));b=b.replace(/%S/g,jsworld._zeroPad(a.getSeconds(),2));b=b.replace(/%T/g,jsworld._zeroPad(a.getHours(),2)+":"+jsworld._zeroPad(a.getMinutes(),2)+":"+jsworld._zeroPad(a.getSeconds(),2));b=b.replace(/%w/g,this.lc.day[a.getDay()]);b=b.replace(/%y/g,(new String(a.getFullYear())).substring(2));b=b.replace(/%Y/g,a.getFullYear());b=b.replace(/%Z/g,"");b=b.replace(/%[a-zA-Z]/g,"");return b};this._hours12=function(a){if(a===0)return 12;else if(a>12)return a-12;else return a};this._getAmPm=function(a){if(a===0||a>12)return this.lc.pm;else return this.lc.am}};jsworld.MonetaryFormatter=function(a,b,c){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance";this.lc=a;this.currencyFractionDigits={AFN:0,ALL:0,AMD:0,BHD:3,BIF:0,BYR:0,CLF:0,CLP:0,COP:0,CRC:0,DJF:0,GNF:0,GYD:0,HUF:0,IDR:0,IQD:0,IRR:0,ISK:0,JOD:3,JPY:0,KMF:0,KRW:0,KWD:3,LAK:0,LBP:0,LYD:3,MGA:0,MMK:0,MNT:0,MRO:0,MUR:0,OMR:3,PKR:0,PYG:0,RSD:0,RWF:0,SLL:0,SOS:0,STD:0,SYP:0,TND:3,TWD:0,TZS:0,UGX:0,UZS:0,VND:0,VUV:0,XAF:0,XOF:0,XPF:0,YER:0,ZMK:0};if(typeof b=="string"){this.currencyCode=b.toUpperCase();var d=this.currencyFractionDigits[this.currencyCode];if(typeof d!="number")d=2;this.lc.frac_digits=d;this.lc.int_frac_digits=d}else{this.currencyCode=this.lc.int_curr_symbol.substring(0,3).toUpperCase()}this.intSep=this.lc.int_curr_symbol.charAt(3);if(this.currencyCode==this.lc.int_curr_symbol.substring(0,3)){this.internationalFormatting=false;this.curSym=this.lc.currency_symbol}else{if(typeof c=="string"){this.curSym=c;this.internationalFormatting=false}else{this.internationalFormatting=true}}this.getCurrencySymbol=function(){return this.curSym};this.currencySymbolPrecedes=function(a){if(typeof a=="string"&&a=="i"){if(this.lc.int_p_cs_precedes==1)return true;else return false}else{if(this.internationalFormatting){if(this.lc.int_p_cs_precedes==1)return true;else return false}else{if(this.lc.p_cs_precedes==1)return true;else return false}}};this.getDecimalPoint=function(){return this.lc.mon_decimal_point};this.getFractionalDigits=function(a){if(typeof a=="string"&&a=="i"){return this.lc.int_frac_digits}else{if(this.internationalFormatting)return this.lc.int_frac_digits;else return this.lc.frac_digits}};this.format=function(a,b){var c;if(typeof a=="string"){a=jsworld._trim(a);c=parseFloat(a);if(typeof c!="number"||isNaN(c))throw"Error: Amount string not a number"}else if(typeof a=="number"){c=a}else{throw"Error: Amount not a number"}var d=jsworld._getPrecision(b);if(d==-1){if(this.internationalFormatting||jsworld._hasOption("i",b))d=this.lc.int_frac_digits;else d=this.lc.frac_digits}c=Math.round(c*Math.pow(10,d))/Math.pow(10,d);var e=jsworld._splitNumber(String(c));var f;if(c===0)f="0";else f=jsworld._hasOption("^",b)?e.integer:jsworld._formatIntegerPart(e.integer,this.lc.mon_grouping,this.lc.mon_thousands_sep);var g;if(d==-1){if(this.internationalFormatting||jsworld._hasOption("i",b))g=jsworld._formatFractionPart(e.fraction,this.lc.int_frac_digits);else g=jsworld._formatFractionPart(e.fraction,this.lc.frac_digits)}else{g=jsworld._formatFractionPart(e.fraction,d)}var h;if(this.lc.frac_digits>0||g.length)h=f+this.lc.mon_decimal_point+g;else h=f;if(jsworld._hasOption("~",b)){return h}else{var i=jsworld._hasOption("!",b)?true:false;var j=c<0?"-":"+";if(this.internationalFormatting||jsworld._hasOption("i",b)){if(i)return this._formatAsInternationalCurrencyWithNoSym(j,h);else return this._formatAsInternationalCurrency(j,h)}else{if(i)return this._formatAsLocalCurrencyWithNoSym(j,h);else return this._formatAsLocalCurrency(j,h)}}};this._formatAsLocalCurrency=function(a,b){if(a=="+"){if(this.lc.p_sign_posn===0&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return"("+b+this.curSym+")"}else if(this.lc.p_sign_posn===0&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return"("+this.curSym+b+")"}else if(this.lc.p_sign_posn===0&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return"("+b+" "+this.curSym+")"}else if(this.lc.p_sign_posn===0&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return"("+this.curSym+" "+b+")"}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+b+this.curSym}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+this.curSym+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+b+" "+this.curSym}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+this.curSym+" "+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+" "+b+this.curSym}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+this.curSym+b}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.curSym+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.curSym+b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.curSym+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.curSym+" "+b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+this.curSym+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.curSym+b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign+this.curSym}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+this.curSym+b}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.lc.positive_sign+this.curSym}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+this.curSym+" "+b}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign+" "+this.curSym}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+this.curSym+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.curSym+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.curSym+this.lc.positive_sign+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.curSym+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.curSym+this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+this.curSym+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.curSym+" "+this.lc.positive_sign+b}}else if(a=="-"){if(this.lc.n_sign_posn===0&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return"("+b+this.curSym+")"}else if(this.lc.n_sign_posn===0&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return"("+this.curSym+b+")"}else if(this.lc.n_sign_posn===0&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return"("+b+" "+this.curSym+")"}else if(this.lc.n_sign_posn===0&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return"("+this.curSym+" "+b+")"}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+b+this.curSym}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+this.curSym+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+b+" "+this.curSym}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+this.curSym+" "+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+" "+b+this.curSym}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+this.curSym+b}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.curSym+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.curSym+b+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.curSym+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.curSym+" "+b+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+this.curSym+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.curSym+b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign+this.curSym}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+this.curSym+b}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign+this.curSym}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+this.curSym+" "+b}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign+" "+this.curSym}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+this.curSym+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.curSym+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.curSym+this.lc.negative_sign+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.curSym+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.curSym+this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+this.curSym+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.curSym+" "+this.lc.negative_sign+b}}throw"Error: Invalid POSIX LC MONETARY definition"};this._formatAsInternationalCurrency=function(a,b){if(a=="+"){if(this.lc.int_p_sign_posn===0&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return"("+b+this.currencyCode+")"}else if(this.lc.int_p_sign_posn===0&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return"("+this.currencyCode+b+")"}else if(this.lc.int_p_sign_posn===0&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return"("+b+this.intSep+this.currencyCode+")"}else if(this.lc.int_p_sign_posn===0&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return"("+this.currencyCode+this.intSep+b+")"}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+b+this.currencyCode}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.currencyCode+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+b+this.intSep+this.currencyCode}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.currencyCode+this.intSep+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+this.intSep+b+this.currencyCode}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+this.currencyCode+b}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.currencyCode+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.currencyCode+b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.currencyCode+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.currencyCode+this.intSep+b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.currencyCode+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.currencyCode+b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign+this.currencyCode}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.currencyCode+b}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign+this.currencyCode}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.currencyCode+this.intSep+b}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign+this.intSep+this.currencyCode}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+this.currencyCode+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.currencyCode+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.currencyCode+this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.currencyCode+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.currencyCode+this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.currencyCode+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.currencyCode+this.intSep+this.lc.positive_sign+b}}else if(a=="-"){if(this.lc.int_n_sign_posn===0&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return"("+b+this.currencyCode+")"}else if(this.lc.int_n_sign_posn===0&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return"("+this.currencyCode+b+")"}else if(this.lc.int_n_sign_posn===0&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return"("+b+this.intSep+this.currencyCode+")"}else if(this.lc.int_n_sign_posn===0&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return"("+this.currencyCode+this.intSep+b+")"}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+b+this.currencyCode}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.currencyCode+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+b+this.intSep+this.currencyCode}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.currencyCode+this.intSep+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+this.intSep+b+this.currencyCode}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+this.currencyCode+b}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.currencyCode+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.currencyCode+b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.currencyCode+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.currencyCode+this.intSep+b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.currencyCode+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.currencyCode+b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign+this.currencyCode}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.currencyCode+b}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign+this.currencyCode}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.currencyCode+this.intSep+b}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign+this.intSep+this.currencyCode}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+this.currencyCode+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.currencyCode+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.currencyCode+this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.currencyCode+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.currencyCode+this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.currencyCode+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.currencyCode+this.intSep+this.lc.negative_sign+b}}throw"Error: Invalid POSIX LC MONETARY definition"};this._formatAsLocalCurrencyWithNoSym=function(a,b){if(a=="+"){if(this.lc.p_sign_posn===0){return"("+b+")"}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+b}}else if(a=="-"){if(this.lc.n_sign_posn===0){return"("+b+")"}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+b}}throw"Error: Invalid POSIX LC MONETARY definition"};this._formatAsInternationalCurrencyWithNoSym=function(a,b){if(a=="+"){if(this.lc.int_p_sign_posn===0){return"("+b+")"}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+b}}else if(a=="-"){if(this.lc.int_n_sign_posn===0){return"("+b+")"}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+b}}throw"Error: Invalid POSIX LC_MONETARY definition"}};jsworld.NumericParser=function(a){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance";this.lc=a;this.parse=function(a){if(typeof a!="string")throw"Parse error: Argument must be a string";var b=jsworld._trim(a);b=jsworld._stringReplaceAll(a,this.lc.thousands_sep,"");b=jsworld._stringReplaceAll(b,this.lc.decimal_point,".");if(jsworld._isNumber(b))return parseFloat(b,10);else throw"Parse error: Invalid number string"}};jsworld.DateTimeParser=function(a){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance.";this.lc=a;this.parseTime=function(a){if(typeof a!="string")throw"Parse error: Argument must be a string";var b=this._extractTokens(this.lc.t_fmt,a);var c=false;if(b.hour!==null&&b.minute!==null&&b.second!==null){c=true}else if(b.hourAmPm!==null&&b.am!==null&&b.minute!==null&&b.second!==null){if(b.am){b.hour=parseInt(b.hourAmPm,10)}else{if(b.hourAmPm==12)b.hour=0;else b.hour=parseInt(b.hourAmPm,10)+12}c=true}if(c)return jsworld._zeroPad(b.hour,2)+":"+jsworld._zeroPad(b.minute,2)+":"+jsworld._zeroPad(b.second,2);else throw"Parse error: Invalid/ambiguous time string"};this.parseDate=function(a){if(typeof a!="string")throw"Parse error: Argument must be a string";var b=this._extractTokens(this.lc.d_fmt,a);var c=false;if(b.year!==null&&b.month!==null&&b.day!==null){c=true}if(c)return jsworld._zeroPad(b.year,4)+"-"+jsworld._zeroPad(b.month,2)+"-"+jsworld._zeroPad(b.day,2);else throw"Parse error: Invalid date string"};this.parseDateTime=function(a){if(typeof a!="string")throw"Parse error: Argument must be a string";var b=this._extractTokens(this.lc.d_t_fmt,a);var c=false;var d=false;if(b.hour!==null&&b.minute!==null&&b.second!==null){c=true}else if(b.hourAmPm!==null&&b.am!==null&&b.minute!==null&&b.second!==null){if(b.am){b.hour=parseInt(b.hourAmPm,10)}else{if(b.hourAmPm==12)b.hour=0;else b.hour=parseInt(b.hourAmPm,10)+12}c=true}if(b.year!==null&&b.month!==null&&b.day!==null){d=true}if(d&&c)return jsworld._zeroPad(b.year,4)+"-"+jsworld._zeroPad(b.month,2)+"-"+jsworld._zeroPad(b.day,2)+" "+jsworld._zeroPad(b.hour,2)+":"+jsworld._zeroPad(b.minute,2)+":"+jsworld._zeroPad(b.second,2);else throw"Parse error: Invalid/ambiguous date/time string"};this._extractTokens=function(a,b){var c={year:null,month:null,day:null,hour:null,hourAmPm:null,am:null,minute:null,second:null,weekday:null};while(a.length>0){if(a.charAt(0)=="%"&&a.charAt(1)!=""){var d=a.substring(0,2);if(d=="%%"){b=b.substring(1)}else if(d=="%a"){for(var e=0;e31)throw"Parse error: Unrecognised day of the month (%e)";b=b.substring(f.length)}else if(d=="%F"){if(/^\d\d\d\d/.test(b)){c.year=parseInt(b.substring(0,4),10);b=b.substring(4)}else{throw"Parse error: Unrecognised date (%F)"}if(jsworld._stringStartsWith(b,"-"))b=b.substring(1);else throw"Parse error: Unrecognised date (%F)";if(/^0[1-9]|1[0-2]/.test(b)){c.month=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised date (%F)";if(jsworld._stringStartsWith(b,"-"))b=b.substring(1);else throw"Parse error: Unrecognised date (%F)";if(/^0[1-9]|[1-2][0-9]|3[0-1]/.test(b)){c.day=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised date (%F)"}else if(d=="%H"){if(/^[0-1][0-9]|2[0-3]/.test(b)){c.hour=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised hour (%H)"}else if(d=="%I"){if(/^0[1-9]|1[0-2]/.test(b)){c.hourAmPm=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised hour (%I)"}else if(d=="%k"){var g=b.match(/^(\d{1,2})/);c.hour=parseInt(g,10);if(isNaN(c.hour)||c.hour<0||c.hour>23)throw"Parse error: Unrecognised hour (%k)";b=b.substring(g.length)}else if(d=="%l"){var g=b.match(/^(\d{1,2})/);c.hourAmPm=parseInt(g,10);if(isNaN(c.hourAmPm)||c.hourAmPm<1||c.hourAmPm>12)throw"Parse error: Unrecognised hour (%l)";b=b.substring(g.length)}else if(d=="%m"){if(/^0[1-9]|1[0-2]/.test(b)){c.month=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised month (%m)"}else if(d=="%M"){if(/^[0-5][0-9]/.test(b)){c.minute=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised minute (%M)"}else if(d=="%n"){if(b.charAt(0)=="\n")b=b.substring(1);else throw"Parse error: Unrecognised new line (%n)"}else if(d=="%p"){if(jsworld._stringStartsWith(b,this.lc.am)){c.am=true;b=b.substring(this.lc.am.length)}else if(jsworld._stringStartsWith(b,this.lc.pm)){c.am=false;b=b.substring(this.lc.pm.length)}else throw"Parse error: Unrecognised AM/PM value (%p)"}else if(d=="%P"){if(jsworld._stringStartsWith(b,this.lc.am.toLowerCase())){c.am=true;b=b.substring(this.lc.am.length)}else if(jsworld._stringStartsWith(b,this.lc.pm.toLowerCase())){c.am=false;b=b.substring(this.lc.pm.length)}else throw"Parse error: Unrecognised AM/PM value (%P)"}else if(d=="%R"){if(/^[0-1][0-9]|2[0-3]/.test(b)){c.hour=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised time (%R)";if(jsworld._stringStartsWith(b,":"))b=b.substring(1);else throw"Parse error: Unrecognised time (%R)";if(/^[0-5][0-9]/.test(b)){c.minute=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised time (%R)"}else if(d=="%S"){if(/^[0-5][0-9]/.test(b)){c.second=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised second (%S)"}else if(d=="%T"){if(/^[0-1][0-9]|2[0-3]/.test(b)){c.hour=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised time (%T)";if(jsworld._stringStartsWith(b,":"))b=b.substring(1);else throw"Parse error: Unrecognised time (%T)";if(/^[0-5][0-9]/.test(b)){c.minute=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised time (%T)";if(jsworld._stringStartsWith(b,":"))b=b.substring(1);else throw"Parse error: Unrecognised time (%T)";if(/^[0-5][0-9]/.test(b)){c.second=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised time (%T)"}else if(d=="%w"){if(/^\d/.test(b)){c.weekday=parseInt(b.substring(0,1),10);b=b.substring(1)}else throw"Parse error: Unrecognised weekday number (%w)"}else if(d=="%y"){if(/^\d\d/.test(b)){var h=parseInt(b.substring(0,2),10);if(h>50)c.year=1900+h;else c.year=2e3+h;b=b.substring(2)}else throw"Parse error: Unrecognised year (%y)"}else if(d=="%Y"){if(/^\d\d\d\d/.test(b)){c.year=parseInt(b.substring(0,4),10);b=b.substring(4)}else throw"Parse error: Unrecognised year (%Y)"}else if(d=="%Z"){if(a.length===0)break}a=a.substring(2)}else{if(a.charAt(0)!=b.charAt(0))throw'Parse error: Unexpected symbol "'+b.charAt(0)+'" in date/time string';a=a.substring(1);b=b.substring(1)}}return c}};jsworld.MonetaryParser=function(a){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance";this.lc=a;this.parse=function(a){if(typeof a!="string")throw"Parse error: Argument must be a string";var b=this._detectCurrencySymbolType(a);var c,d;if(b=="local"){c="local";d=a.replace(this.lc.getCurrencySymbol(),"")}else if(b=="int"){c="int";d=a.replace(this.lc.getIntCurrencySymbol(),"")}else if(b=="none"){c="local";d=a}else throw"Parse error: Internal assert failure";d=jsworld._stringReplaceAll(d,this.lc.mon_thousands_sep,"");d=d.replace(this.lc.mon_decimal_point,".");d=d.replace(/\s*/g,"");d=this._removeLocalNonNegativeSign(d,c);d=this._normaliseNegativeSign(d,c);if(jsworld._isNumber(d))return parseFloat(d,10);else throw"Parse error: Invalid currency amount string"};this._detectCurrencySymbolType=function(a){if(this.lc.getCurrencySymbol().length>this.lc.getIntCurrencySymbol().length){if(a.indexOf(this.lc.getCurrencySymbol())!=-1)return"local";else if(a.indexOf(this.lc.getIntCurrencySymbol())!=-1)return"int";else return"none"}else{if(a.indexOf(this.lc.getIntCurrencySymbol())!=-1)return"int";else if(a.indexOf(this.lc.getCurrencySymbol())!=-1)return"local";else return"none"}};this._removeLocalNonNegativeSign=function(a,b){a=a.replace(this.lc.positive_sign,"");if((b=="local"&&this.lc.p_sign_posn===0||b=="int"&&this.lc.int_p_sign_posn===0)&&/\(\d+\.?\d*\)/.test(a)){a=a.replace("(","");a=a.replace(")","")}return a};this._normaliseNegativeSign=function(a,b){a=a.replace(this.lc.negative_sign,"-");if(b=="local"&&this.lc.n_sign_posn===0||b=="int"&&this.lc.int_n_sign_posn===0){if(/^\(\d+\.?\d*\)$/.test(a)){a=a.replace("(","");a=a.replace(")","");return"-"+a}}if(b=="local"&&this.lc.n_sign_posn==2||b=="int"&&this.lc.int_n_sign_posn==2){if(/^\d+\.?\d*-$/.test(a)){a=a.replace("-","");return"-"+a}}if(b=="local"&&this.lc.n_cs_precedes===0&&this.lc.n_sign_posn==3||b=="local"&&this.lc.n_cs_precedes===0&&this.lc.n_sign_posn==4||b=="int"&&this.lc.int_n_cs_precedes===0&&this.lc.int_n_sign_posn==3||b=="int"&&this.lc.int_n_cs_precedes===0&&this.lc.int_n_sign_posn==4){if(/^\d+\.?\d*-$/.test(a)){a=a.replace("-","");return"-"+a}}return a}} + + +if(typeof POSIX_LC == "undefined") var POSIX_LC = {}; + +POSIX_LC.en_US = { + "decimal_point" : ".", + "thousands_sep" : ",", + "grouping" : "3", + "abday" : ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"], + "day" : ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"], + "abmon" : ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"], + "mon" : ["January","February","March","April","May","June","July","August","September","October","November","December"], + "d_fmt" : "%m/%e/%y", + "t_fmt" : "%I:%M:%S %p", + "d_t_fmt" : "%B %e, %Y %I:%M:%S %p %Z", + "am_pm" : ["AM","PM"], + "int_curr_symbol" : "USD ", + "currency_symbol" : "\u0024", + "mon_decimal_point" : ".", + "mon_thousands_sep" : ",", + "mon_grouping" : "3", + "positive_sign" : "", + "negative_sign" : "-", + "int_frac_digits" : 2, + "frac_digits" : 2, + "p_cs_precedes" : 1, + "n_cs_precedes" : 1, + "p_sep_by_space" : 0, + "n_sep_by_space" : 0, + "p_sign_posn" : 1, + "n_sign_posn" : 1, + "int_p_cs_precedes" : 1, + "int_n_cs_precedes" : 1, + "int_p_sep_by_space" : 0, + "int_n_sep_by_space" : 0, + "int_p_sign_posn" : 1, + "int_n_sign_posn" : 1 +} + +if(typeof POSIX_LC == "undefined") var POSIX_LC = {}; + +POSIX_LC.fr_FR = { + "decimal_point" : ",", + "thousands_sep" : "\u00a0", + "grouping" : "3", + "abday" : ["dim.","lun.","mar.", + "mer.","jeu.","ven.", + "sam."], + "day" : ["dimanche","lundi","mardi", + "mercredi","jeudi","vendredi", + "samedi"], + "abmon" : ["janv.","f\u00e9vr.","mars", + "avr.","mai","juin", + "juil.","ao\u00fbt","sept.", + "oct.","nov.","d\u00e9c."], + "mon" : ["janvier","f\u00e9vrier","mars", + "avril","mai","juin", + "juillet","ao\u00fbt","septembre", + "octobre","novembre","d\u00e9cembre"], + "d_fmt" : "%d/%m/%y", + "t_fmt" : "%H:%M:%S", + "d_t_fmt" : "%e %B %Y %H:%M:%S %Z", + "am_pm" : ["AM","PM"], + "int_curr_symbol" : "EUR ", + "currency_symbol" : "\u20ac", + "mon_decimal_point" : ",", + "mon_thousands_sep" : "\u00a0", + "mon_grouping" : "3", + "positive_sign" : "", + "negative_sign" : "-", + "int_frac_digits" : 2, + "frac_digits" : 2, + "p_cs_precedes" : 0, + "n_cs_precedes" : 0, + "p_sep_by_space" : 1, + "n_sep_by_space" : 1, + "p_sign_posn" : 1, + "n_sign_posn" : 1, + "int_p_cs_precedes" : 0, + "int_n_cs_precedes" : 0, + "int_p_sep_by_space" : 1, + "int_n_sep_by_space" : 1, + "int_p_sign_posn" : 1, + "int_n_sign_posn" : 1 +}; + +/** https://github.com/csnover/js-iso8601 */(function(n,f){var u=n.parse,c=[1,4,5,6,7,10,11];n.parse=function(t){var i,o,a=0;if(o=/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(t)){for(var v=0,r;r=c[v];++v)o[r]=+o[r]||0;o[2]=(+o[2]||1)-1,o[3]=+o[3]||1,o[8]!=="Z"&&o[9]!==f&&(a=o[10]*60+o[11],o[9]==="+"&&(a=0-a)),i=n.UTC(o[1],o[2],o[3],o[4],o[5]+a,o[6],o[7])}else i=u?u(t):NaN;return i}})(Date) + +/*! + * geo-location-javascript v0.4.3 + * http://code.google.com/p/geo-location-javascript/ + * + * Copyright (c) 2009 Stan Wiechers + * Licensed under the MIT licenses. + * + * Revision: $Rev: 68 $: + * Author: $Author: whoisstan $: + * Date: $Date: 2010-02-15 13:42:19 +0100 (Mon, 15 Feb 2010) $: + */ +var geo_position_js=function() { + + var pub = {}; + var provider=null; + + pub.getCurrentPosition = function(successCallback,errorCallback,options) + { + provider.getCurrentPosition(successCallback, errorCallback,options); + } + + pub.init = function() + { + try + { + if (typeof(geo_position_js_simulator)!="undefined") + { + provider=geo_position_js_simulator; + } + else if (typeof(bondi)!="undefined" && typeof(bondi.geolocation)!="undefined") + { + provider=bondi.geolocation; + } + else if (typeof(navigator.geolocation)!="undefined") + { + provider=navigator.geolocation; + pub.getCurrentPosition = function(successCallback, errorCallback, options) + { + function _successCallback(p) + { + //for mozilla geode,it returns the coordinates slightly differently + if(typeof(p.latitude)!="undefined") + { + successCallback({timestamp:p.timestamp, coords: {latitude:p.latitude,longitude:p.longitude}}); + } + else + { + successCallback(p); + } + } + provider.getCurrentPosition(_successCallback,errorCallback,options); + } + } + else if(typeof(window.google)!="undefined" && typeof(google.gears)!="undefined") + { + provider=google.gears.factory.create('beta.geolocation'); + } + else if ( typeof(Mojo) !="undefined" && typeof(Mojo.Service.Request)!="Mojo.Service.Request") + { + provider=true; + pub.getCurrentPosition = function(successCallback, errorCallback, options) + { + + parameters={}; + if(options) + { + //http://developer.palm.com/index.php?option=com_content&view=article&id=1673#GPS-getCurrentPosition + if (options.enableHighAccuracy && options.enableHighAccuracy==true) + { + parameters.accuracy=1; + } + if (options.maximumAge) + { + parameters.maximumAge=options.maximumAge; + } + if (options.responseTime) + { + if(options.responseTime<5) + { + parameters.responseTime=1; + } + else if (options.responseTime<20) + { + parameters.responseTime=2; + } + else + { + parameters.timeout=3; + } + } + } + + + r=new Mojo.Service.Request('palm://com.palm.location', { + method:"getCurrentPosition", + parameters:parameters, + onSuccess: function(p){successCallback({timestamp:p.timestamp, coords: {latitude:p.latitude, longitude:p.longitude,heading:p.heading}});}, + onFailure: function(e){ + if (e.errorCode==1) + { + errorCallback({code:3,message:"Timeout"}); + } + else if (e.errorCode==2) + { + errorCallback({code:2,message:"Position Unavailable"}); + } + else + { + errorCallback({code:0,message:"Unknown Error: webOS-code"+errorCode}); + } + } + }); + } + + } + else if (typeof(device)!="undefined" && typeof(device.getServiceObject)!="undefined") + { + provider=device.getServiceObject("Service.Location", "ILocation"); + + //override default method implementation + pub.getCurrentPosition = function(successCallback, errorCallback, options) + { + function callback(transId, eventCode, result) { + if (eventCode == 4) + { + errorCallback({message:"Position unavailable", code:2}); + } + else + { + //no timestamp of location given? + successCallback({timestamp:null, coords: {latitude:result.ReturnValue.Latitude, longitude:result.ReturnValue.Longitude, altitude:result.ReturnValue.Altitude,heading:result.ReturnValue.Heading}}); + } + } + //location criteria + var criteria = new Object(); + criteria.LocationInformationClass = "BasicLocationInformation"; + //make the call + provider.ILocation.GetLocation(criteria,callback); + } + } + } + catch (e){ + alert("error="+e); + if(typeof(console)!="undefined") + { + console.log(e); + } + return false; + } + return provider!=null; + } + + + return pub; +}(); +// Couldn't get unminified version to work , go here for docs => https://github.com/iamnoah/writeCapture +(function(E,a){var j=a.document;function A(Q){var Z=j.createElement("div");j.body.insertBefore(Z,null);E.replaceWith(Z,'\n
\n
\n
\n \n\n
\n
\n \n
\n

'); + __out.push(__sanitize(t('Invite Link'))); + __out.push(' '); + __out.push(__sanitize(USER.referral_url)); + __out.push('

\n\n \n\n
\n\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/clients/login": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + __out.push('
\n\t

'); + __out.push(__sanitize(t('Sign In'))); + __out.push('

\n\t
\n\t\t
\n\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\n\t\t\t
\n\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\n\t\t\t
\n\n
\n\n

'); + __out.push(__sanitize(t('Forgot Password?'))); + __out.push('

\n\n\t\t
\n\t
\n
\n\n
\n
\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/clients/modules/credit_card": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + var printCard; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + if (this.cards === "new") { + __out.push('\n
\n
\n
\n
\n
\n
\n \n \n
\n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n
\n
\n \n \n
\n
\n
\n \n \n
\n
\n
\n \n \n
\n
\n
\n \n
\n
\n
\n'); + } else { + __out.push('\n '); + printCard = __bind(function(card, index) { + var exp, style; + __out.push('\n
\n '); + style = "background-position:-173px"; + __out.push('\n '); + if (card.get("card_type") === "Visa") { + style = "background-position:0px"; + } + __out.push('\n '); + if (card.get("card_type") === "MasterCard") { + style = "background-position:-42px"; + } + __out.push('\n '); + if (card.get("card_type") === "American Express") { + style = "background-position:-130px"; + } + __out.push('\n '); + if (card.get("card_type") === "Discover Card") { + style = "background-position:-85px"; + } + __out.push('\n
\n
\n ****'); + __out.push(__sanitize(card.get("card_number"))); + __out.push('\n \n '); + if (card.get("card_expiration")) { + __out.push('\n '); + __out.push(__sanitize(t('Expiry'))); + __out.push('\n '); + exp = card.get('card_expiration').split('-'); + __out.push('\n '); + __out.push(__sanitize("" + exp[0] + "-" + exp[1])); + __out.push('\n '); + } + __out.push('\n \n \n \n '); + if (card.get("default")) { + __out.push('\n ('); + __out.push(__sanitize(t('default card'))); + __out.push(')\n '); + } + __out.push('\n '); + if (this.cards.length > 1 && !card.get("default")) { + __out.push('\n '); + __out.push(__sanitize(t('make default'))); + __out.push('\n '); + } + __out.push('\n \n '); + __out.push(__sanitize(t('Edit'))); + __out.push('\n \n '); + if (this.cards.length > 1) { + __out.push('\n '); + __out.push(__sanitize(t('Delete'))); + __out.push('\n '); + } + __out.push('\n
\n '); + _.each(this.cards.models, printCard); + __out.push('\n
\n
\n\n'); + } + __out.push('\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/clients/modules/sub_header": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + __out.push('
\n
'); + __out.push(__sanitize(this.heading)); + __out.push('
\n
\n '); + if (window.USER.first_name) { + __out.push('\n '); + __out.push(__sanitize(t('Hello Greeting', { + name: USER.first_name + }))); + __out.push('\n '); + } + __out.push('\n
\n
\n
\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/clients/promotions": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + var promo, _i, _len, _ref; + __out.push(require('templates/clients/modules/sub_header').call(this, { + heading: t("Promotions") + })); + __out.push('\n\n
\n
\n
\n \n \n
\n
\n \n \n\n \n
\n '); + if (this.promos.length > 0) { + __out.push('\n
\n

'); + __out.push(__sanitize(t('Your Available Promotions'))); + __out.push('

\n \n \n\n \n \n \n \n \n \n \n \n '); + _ref = this.promos; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + promo = _ref[_i]; + __out.push('\n \n \n \n \n \n \n '); + } + __out.push('\n \n
'); + __out.push(__sanitize(t('Code'))); + __out.push(''); + __out.push(__sanitize(t('Details'))); + __out.push(''); + __out.push(__sanitize(t('Starts'))); + __out.push(''); + __out.push(__sanitize(t('Expires'))); + __out.push('
'); + __out.push(__sanitize(promo.code)); + __out.push(''); + __out.push(__sanitize(promo.description)); + __out.push(''); + __out.push(__sanitize(app.helpers.formatDate(promo.starts_at, true, "America/Los_Angeles"))); + __out.push(''); + __out.push(__sanitize(app.helpers.formatDate(promo.ends_at, true, "America/Los_Angeles"))); + __out.push('
\n
\n '); + } else { + __out.push('\n\n

'); + __out.push(__sanitize(t('No Active Promotions'))); + __out.push('

\n '); + } + __out.push('\n\n
\n
\n
\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/clients/request": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + var showFavoriteLocation; + showFavoriteLocation = function(location, index) { + var alphabet; + __out.push('\n '); + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + __out.push('\n
\n '); + __out.push(__sanitize(location.nickname)); + return __out.push('\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n

'); + __out.push(__sanitize(t('Driver Name:'))); + __out.push('

\n

\n
\n

'); + __out.push(__sanitize(t('Driver #:'))); + __out.push('

\n

\n
\n

'); + __out.push(__sanitize(t('Pickup Address:'))); + __out.push('

\n

\n
\n ');
+      __out.push(__sanitize(t('Add to Favorite Locations')));
+      __out.push('\n
\n
\n

\n '); + __out.push(__sanitize(t('Nickname:'))); + __out.push('\n \n \n \n \n
\n
\n
\n
\n

'); + __out.push(__sanitize(t('Your last trip'))); + __out.push('

\n
\n \n ');
+      __out.push(__sanitize(t('Star')));
+      __out.push('\n ');
+      __out.push(__sanitize(t('Star')));
+      __out.push('\n ');
+      __out.push(__sanitize(t('Star')));
+      __out.push('\n ');
+      __out.push(__sanitize(t('Star')));
+      __out.push('\n ');
+      __out.push(__sanitize(t('Star')));
+      __out.push('\n \n \n
\n \n
\n \n
\n \n
\n \n\n
\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/shared/menu": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + __out.push('\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "translations/en": function(exports, require, module) {(function() { + exports.translations = { + "Uber": "Uber", + "Sign Up": "Sign Up", + "Ride Request": "Ride Request", + "Invite Friends": "Invite Friends", + "Promotions": "Promotions", + "Billing": "Billing", + "Settings": "Settings", + "Forgot Password?": "Forgot Password?", + "Password Recovery": "Password Recovery", + "Login": "Login", + "Trip Detail": "Trip Detail", + "Password Reset": "Password Reset", + "Confirm Email": "Confirm Email", + "Request Ride": "Request Ride", + "Credit Card Number": "Credit Card Number", + "month": "month", + "01-Jan": "01-Jan", + "02-Feb": "02-Feb", + "03-Mar": "03-Mar", + "04-Apr": "04-Apr", + "05-May": "05-May", + "06-Jun": "06-Jun", + "07-Jul": "07-Jul", + "08-Aug": "08-Aug", + "09-Sep": "09-Sep", + "10-Oct": "10-Oct", + "11-Nov": "11-Nov", + "12-Dec": "12-Dec", + "year": "year", + "CVV": "CVV", + "Category": "Category", + "personal": "personal", + "business": "business", + "Default Credit Card": "Default Credit Card", + "Add Credit Card": "Add Credit Card", + "Expiry": "Expiry", + "default card": "default card", + "make default": "make default", + "Edit": "Edit", + "Delete": "Delete", + "Expiry Month": "Expiry Month", + "Expiry Year": "Expiry Year", + "Unable to Verify Card": "Unable to verify card at this time. Please try again later.", + "Credit Card Update Succeeded": "Your card has been successfully updated!", + "Credit Card Update Failed": "We couldn't save your changes. Please try again in a few minutes.", + "Credit Card Delete Succeeded": "Your card has been deleted!", + "Credit Card Delete Failed": "We were unable to delete your card. Please try again later.", + "Credit Card Update Category Succeeded": "Successfully changed card category!", + "Credit Card Update Category Failed": "We couldn't change your card category. Please try again in a few minutes.", + "Credit Card Update Default Succeeded": "Successfully changed default card!", + "Credit Card Update Default Failed": "We couldn't change your default card. Please try again in a few minutes.", + "Hello Greeting": "Hello, <%= name %>", + "Card Ending in": "Card Ending in", + "Trip Map": "Trip Map", + "Amount": "Amount: <%= amount %>", + "Last Attempt to Bill": "Last Attempt to Bill: <%= date %>", + "Charge": "Charge", + "Uber Credit Balance Note": "Your account has an UberCredit balance of <%= amount %>. When billing for trips, we'll deplete your UberCredit balance before applying charges to your credit card.", + "Please Add Credit Card": "Please add a credit card to bill your outstanding charges.", + "Credit Cards": "Credit Cards", + "add a new credit card": "add a new credit card", + "Account Balance": "Account Balance", + "Arrears": "Arrears", + "Billing Succeeded": "Your card was successfully billed.", + "Confirm Email Succeeded": "Successfully confirmed email token, redirecting to log in page...", + "Confirm Email Failed": "Unable to confirm email. Please contact support@uber.com if this problem persists.", + "Email Already Confirmed": "Your email address has already been confirmed, redirecting to log in page...", + "Credit Card Added": "Credit Card Added", + "No Credit Card": "No Credit Card", + "Mobile Number Confirmed": "Mobile Number Confirmed", + "No Confirmed Mobile": "No Confirmed Mobile", + "E-mail Address Confirmed": "E-mail Address Confirmed", + "No Confirmed E-mail": "No Confirmed E-mail", + 'Reply to sign up text': 'Reply "GO" to the text message you received at sign up.', + "Resend text message": "Resend text message", + "Click sign up link": "Click the link in the email you received at sign up.", + "Resend email": "Resend email", + "Add a credit card to ride": "Add a credit card and you'll be ready to ride Uber.", + "Your Most Recent Trip": "Your Most Recent Trip", + "details": "details", + "Your Trip History ": "Your Trip History ", + "Status": "Status", + "Here's how it works:": "Here's how it works:", + "Show all trips": "Show all trips", + "Set your location:": "Set your location:", + "App search for address": "iPhone/Android app: fix the pin or search for an address", + "SMS text address": "SMS: text your address to UBRCAB (827222)", + "Confirm pickup request": "Confirm your pickup request", + "Uber sends ETA": "Uber will send you an ETA (usually within 5-10 minutes)", + "Car arrives": "When your car is arriving, Uber will inform you again.", + "Ride to destination": "Hop in the car and tell the driver your destination.", + "Thank your driver": "That’s it! Please thank your driver but remember that your tip is included and no cash is necessary.", + "Trip started here": "Trip started here", + "Trip ended here": "Trip ended here", + "Sending Email": "Sending email...", + "Resend Email Succeeded": "We just sent the email. Please click on the confirmation link you recieve.", + "Resend Email Failed": "There was an error sending the email. Please contact support if the problem persists.", + "Resend Text Succeeded": 'We just sent the text message. Please reply "GO" to the message you recieve. It may take a few minutes for the message to reach you phone.', + "Resend Text Failed": "There was an error sending the text message. Please contact support if the problem persists.", + "Password Reset Error": "There was an error processing your password reset request.", + "New Password": "New Password", + "Forgot Password": "Forgot Password", + "Forgot Password Error": "Your email address could not be found. Please make sure to use the same email address you used when you signed up.", + "Forgot Password Success": "Please check your email for a link to reset your password.", + "Forgot Password Enter Email": 'Enter your email address and Uber will send you a link to reset your password. If you remember your password, you can sign in here.', + "Invite friends": "Invite friends", + "Give $ Get $": "Give $10, Get $10", + "Give $ Get $ Description": "Every friend you invite to Uber gets $10 of Uber credit. After someone you’ve invited takes his/her first ride, you get $10 of Uber credits too!", + "What are you waiting for?": "So, what are you waiting for? Invite away!", + "Tweet": "Tweet", + "Invite Link": "Email or IM this link to your friends:", + "Email Address": "Email Address", + "Reset Password": "Reset Password", + "Enter Promotion Code": "If you have a promotion code, enter it here:", + "Your Active Promotions": "Your Active Promotions", + "Code": "Code", + "Details": "Details", + "Trips Remaining": "Trips Remaining", + "Expires": "Expires", + "No Active Promotions": "There are no active promotions on your account.", + "Your Available Promotions": "Your Available Promotions", + "Where do you want us to pick you up?": "Where do you want us to pick you up?", + "Address to search": "Address to search", + "Search": "Search", + "Driver Name:": "Driver Name:", + "Driver #:": "Driver #:", + "Pickup Address:": "Pickup Address:", + "Add to Favorite Locations": "Add to Favorite Locations", + "Star": "Star", + "Nickname:": "Nickname:", + "Add": "Add", + "Your last trip": "Your last trip", + "Please rate your driver:": "Please rate your driver:", + "Comments: (optional)": "Comments: (optional)", + "Rate Trip": "Rate Trip", + "Pickup time:": "Pickup time:", + "Miles:": "Miles:", + "Trip time:": "Trip time:", + "Fare:": "Fare:", + "Favorite Locations": "Favorite Locations", + "Search Results": "Search Results", + "You have no favorite locations saved.": "You have no favorite locations saved.", + "Loading...": "Loading...", + "Request Pickup": "Request Pickup", + "Cancel Pickup": "Cancel Pickup", + "Requesting Closest Driver": "Requesting the closest driver to pick you up...", + "En Route": "You are currently en route...", + "Rate Last Trip": "Please rate your trip to make another request", + "Rate Before Submitting": "Please rate your trip before submitting the form", + "Address too short": "Address too short", + "or did you mean": "or did you mean", + "Search Address Failed": "Unable to find the given address. Please enter another address close to your location.", + "Sending pickup request...": "Sending pickup request...", + "Cancel Request Prompt": "Are you sure you want to cancel your request?", + "Cancel Request Arrived Prompt": 'Are you sure you want to cancel your request? Your driver has arrived so there is a $10 cancellation fee. It may help to call your driver now', + "Favorite Location Nickname Length Error": "Nickname has to be atleast 3 characters", + "Favorite Location Save Succeeded": "Location Saved!", + "Favorite Location Save Failed": "Unable to save your location. Please try again later.", + "Favorite Location Title": "Favorite Location <%= id %>", + "Search Location Title": "Search Location <%= id %>", + "ETA Message": "ETA: Around <%= minutes %> Minutes", + "Nearest Cab Message": "The closest driver is approximately <%= minutes %> minute(s) away", + "Arrival ETA Message": "Your Uber will arrive in about <%= minutes %> minute(s)", + "Arriving Now Message": "Your Uber is arriving now...", + "Rating Driver Failed": "Unable to contact server. Please try again later or email support if this issue persists.", + "Account Information": "Account Information", + "Mobile Phone Information": "Mobile Phone Information", + "settings": "settings", + "Information": "Information", + "Picture": "Picture", + "Change password": "Change password", + "Your current Picture": "Your current Picture", + "Your Favorite Locations": "Your Favorite Locations", + "You have no favorite locations saved.": "You have no favorite locations saved.", + "Purpose of Mobile": "We send text messages to your mobile phone to tell you when your driver is arriving. You can also request trips using text messages.", + "Country": "Country", + "Mobile Number": "Mobile Number", + "Submit": "Submit", + "Favorite Location": "Favorite Location", + "No Approximate Address": "Could not find an approximate address", + "Address:": "Address:", + "Information Update Succeeded": "Your information has been updated!", + "Information Update Failed": "We couldn't update your information. Please try again in few minutes or contact support if the problem persists.", + "Location Delete Succeeded": "Location deleted!", + "Location Delete Failed": "We were unable to delete your favorite location. Please try again later or contact support of the issue persists.", + "Location Edit Succeeded": "Changes Saved!", + "Location Edit Failed": "We couldn't save your changes. Please try again in a few minutes.", + "Picture Update Succeeded": "Your picture has been updated!", + "Picture Update Failed": "We couldn't change your picture. Please try again in a few minutes.", + "Personal Information": "Personal Information", + "Mobile Phone Number": "Mobile Phone Number", + "Payment Information": "Payment Information", + "Purpose of Credit Card": "We keep your credit card on file so that your trip go as fast as possible. You will not be charged until you take a trip.", + "Your card will not be charged until you take a trip.": "Your card will not be charged until you take a trip.", + "Credit Card Number": "Credit Card Number", + "Expiration Date": "Expiration Date", + "Promotion Code": "Promotion Code", + "Enter Promo Here": "If you have a code for a promotion, invitation or group deal, you can enter it here.", + "Promotion Code Input Label": "Promotion, Invite or Groupon Code (optional)", + "Terms and Conditions": "Terms and Conditions", + "HELP": "HELP", + "STOP": "STOP", + "Legal Information": "Legal Information", + "Sign Up Agreement": "By signing up, I agree to the Uber <%= terms_link %> and <%= privacy_link %> and understand that Uber is a request tool, not a transportation carrier.", + "Sign Up Agreement Error": "You must agree to the Uber Terms and Conditions and Privacy Policy to continue.", + "Message and Data Rates Disclosure": "Message and Data Rates May Apply. Reply <%= help_string %> to 827-222 for help. Reply <%= stop_string %> to 827-222 to stop texts. For additional assistance, visit support.uber.com or call (866) 576-1039. Supported Carriers: AT&T, Sprint, Verizon, and T-Mobile.", + "I Agree": "I agree to the Terms & Conditions and Privacy Policy", + "Security Code": "Security Code", + "Type of Card": "Type of Card", + "Personal": "Personal", + "Business": "Business", + "Code": "Code", + "Zip or Postal Code": "Zip or Postal Code", + "Your Trip": "Your Trip", + "Trip Info": "Trip Info", + "Request a fare review": "Request a fare review", + "Fare Review Submitted": "Your fare review has been submitted. We'll get back to you soon about your request. Sorry for any inconvenience this may have caused!", + "Fair Price Consideration": "We're committed to delivering Uber service at a fair price. Before requesting a fare review, please consider:", + "Your Fare Calculation": "Your Fare Calculation", + "Charges": "Charges", + "Discounts": "Discounts", + "Total Charge": "Total Charge", + "Uber pricing information": "Uber pricing information", + "Uber Pricing Information Message": "<%= learn_link %> is published on our website.", + "GPS Point Capture Disclosure": "Due to a finite number of GPS point captures, corners on your trip map may appear cut off or rounded. These minor inaccuracies result in a shorter measured distance, which always results in a cheaper trip.", + "Fare Review Note": "Please elaborate on why this trip requires a fare review. Your comments below will help us better establish the correct price for your trip:", + "Fare Review Error": "There was an error submitting the review. Please ensure that you have a message.", + "Sign In": "Sign In" + }; +}).call(this); +}, "translations/fr": function(exports, require, module) {(function() { + exports.translations = { + "Uber": "Uber", + "Sign Up": "Inscription", + "Ride Request": "Passer une Commande", + "Invite Friends": "Inviter vos Amis", + "Promotions": "Promotions", + "Billing": "Paiement", + "Settings": "Paramètres", + "Forgot Password?": "Mot de passe oublié ?", + "Password Recovery": "Récupération du mot de passe", + "Login": "Connexion", + "Trip Detail": "Détail de la Course", + "Password Reset": "Réinitialisation du mot de passe", + "Confirm Email": "Confirmation de l’e-mail", + "Request Ride": "Passer une Commande", + "Credit Card Number": "Numéro de Carte de Crédit", + "month": "mois", + "01-Jan": "01-Jan", + "02-Feb": "02-Fév", + "03-Mar": "03-Mar", + "04-Apr": "04-Avr", + "05-May": "05-Mai", + "06-Jun": "06-Juin", + "07-Jul": "07-Jui", + "08-Aug": "08-Aoû", + "09-Sep": "09-Sep", + "10-Oct": "10-Oct", + "11-Nov": "11-Nov", + "12-Dec": "12-Déc", + "year": "année", + "CVV": "Code de Sécurité", + "Category": "Type", + "personal": "personnel", + "business": "entreprise", + "Default Credit Card": "Carte par Défaut", + "Add Credit Card": "Ajouter une Carte", + "Expiry": "Expire", + "default card": "carte par défaut", + "make default": "choisir par défaut", + "Edit": "Modifier", + "Delete": "Supprimer", + "Expiry Month": "Mois d’Expiration", + "Expiry Year": "Année d’Expiration", + "Unable to Verify Card": "Impossible de vérifier la carte pour le moment. Merci de réessayer un peu plus tard.", + "Credit Card Update Succeeded": "Votre carte a été mise à jour avec succès !", + "Credit Card Update Failed": "Nous ne pouvons enregistrer vos changements. Merci de réessayer dans quelques minutes.", + "Credit Card Delete Succeeded": "Votre carte a été supprimée !", + "Credit Card Delete Failed": "Nous n’avons pas été en mesure de supprimer votre carte. Merci de réessayer plus tard.", + "Credit Card Update Category Succeeded": "Changement de catégorie de carte réussi !", + "Credit Card Update Category Failed": "Nous ne pouvons pas changer la catégorie de votre carte. Merci de réessayer dans quelques minutes.", + "Credit Card Update Default Succeeded": "Carte par défaut changée avec succès !", + "Credit Card Update Default Failed": "Nous ne pouvons pas changer votre carte par défaut. Merci de réessayer dans quelques minutes.", + "Hello Greeting": "Bonjour, <%= name %>", + "Card Ending in": "La carte expire dans", + "Trip Map": "Carte des Courses", + "Amount": "Montant: <%= amount %>", + "Last Attempt to Bill": "Dernière tentative de prélèvement : <%= date %>", + "Charge": "Débit", + "Uber Credit Balance Note": "Votre compte a un solde de <%= amount %> UberCredits. Lorsque nous facturons des courses, nous réduirons votre solde d’UberCredits avant de prélever votre carte de crédit.", + "Please Add Credit Card": "Merci d’ajouter une carte de crédit pour que nous puissions vous facturer.", + "Credit Cards": "Cartes de crédit", + "add a new credit card": "Ajouter une nouvelle carte de crédit", + "Account Balance": "Solde du compte", + "Arrears": "Arriérés", + "Billing Succeeded": "Votre carte a été correctement débitée.", + "Confirm Email Succeeded": "L’adresse e-mail a bien été validée, vous êtes redirigé vers le tableau de bord...", + "Confirm Email Failed": "Impossible de confirmer l’adresse e-mail. Merci de contacter support@uber.com si le problème persiste.", + "Credit Card Added": "Carte de crédit ajoutée", + "No Credit Card": "Pas de carte de crédit", + "Mobile Number Confirmed": "Numéro de téléphone confirmé", + "No Confirmed Mobile": "Pas de numéro de téléphone confirmé", + "E-mail Address Confirmed": "Adresse e-mail confirmée", + "No Confirmed E-mail": "Pas d’adresse e-mail confirmée", + 'Reply to sign up text': 'Répondre "GO" au SMS que vous avez reçu à l’inscription.', + "Resend text message": "Renvoyer le SMS", + "Click sign up link": "Cliquez sur le lien contenu dans l’e-mail reçu à l’inscription.", + "Resend email": "Renvoyer l’e-mail", + "Add a credit card to ride": "Ajouter une carte de crédit et vous serez prêt à voyager avec Uber.", + "Your Most Recent Trip": "Votre course la plus récente", + "details": "détails", + "Your Trip History": "Historique de votre trajet", + "Status": "Statut", + "Here's how it works:": "Voici comment ça marche :", + "Show all trips": "Montrer toutes les courses", + "Set your location:": "Définir votre position :", + "App search for address": "Application iPhone/Android : positionner la punaise ou rechercher une adresse", + "SMS text address": "SMS : envoyez votre adresse à UBRCAB (827222)", + "Confirm pickup request": "Validez la commande", + "Uber sends ETA": "Uber envoie un temps d’attente estimé (habituellement entre 5 et 10 minutes)", + "Car arrives": "Lorsque votre voiture arrive, Uber vous en informera encore..", + "Ride to destination": "Montez dans la voiture et donnez votre destination au chauffeur.", + "Thank your driver": "C’est tout ! Remerciez le chauffeur mais souvenez-vous que les pourboires sont compris et qu’il n’est pas nécessaire d’avoir du liquide sur soi.", + "Trip started here": "La course a commencé ici.", + "Trip ended here": "La course s’est terminée ici.", + "Sending Email": "Envoi de l’e-mail...", + "Resend Email Succeeded": "Nous venons d’envoyer l’e-mail. Merci de cliquer sur le lien de confirmation que vous avez reçu.", + "Resend Email Failed": "Il y a eu un problème lors de l’envoi de l’email. Merci de contacter le support si le problème persiste.", + "Resend Text Succeeded": 'Nous venons d’envoyer le SMS. Merci de répondre "GO" au message que vous avez reçu. Il se peut que cela prenne quelques minutes pour que le message arrive sur votre téléphone.', + "Resend Text Failed": "Il y a eu un problème lors de l’envoi du SMS. Merci de contacter le support si le problème persiste.", + "Password Reset Error": "Il y a eu une error lors de la réinitialisation de votre mot de passe.", + "New Password:": "Nouveau mot de passe:", + "Forgot Password Error": "Votre nom d’utilisateur / adresse email ne peut être trouvé. Merci d’utiliser la même qu’à l’inscription.", + "Forgot Password Success": "Merci de consulter votre boîte mail pour suivre la demande de ‘réinitialisation de mot de passe.", + "Forgot Password Enter Email": "Merci de saisir votre adresse email et nous vous enverrons un lien vous permettant de réinitialiser votre mot de passe :", + "Invite friends": "Inviter vos amis", + "Give $ Get $": "Donnez $10, Recevez $10", + "Give $ Get $ Description": "Chaque ami que vous invitez à Uber recevra $10 de crédits Uber. Dès lors qu’une personne que vous aurez invité aura utilisé Uber pour la première, vous recevrez $10 de crédits Uber également !", + "What are you waiting for?": "N’attendez plus ! Lancez les invitations !", + "Tweet": "Tweeter", + "Invite Link": "Envoyez ce lien par email ou messagerie instantanée à vos amis :", + "Enter Promotion Code": "Si vous avez un code promo, saisissez-le ici:", + "Your Active Promotions": "Vos Codes Promos Actifs", + "Code": "Code", + "Details": "Détails", + "Trips Remaining": "Courses restantes", + "Expires": "Expire", + "No Active Promotions": "Vous n’avez pas de code promo actif.", + "Your Available Promotions": "Votres Promos Disponibles", + "Where do you want us to pick you up?": "Où souhaitez-vous que nous vous prenions en charge ?", + "Address to search": "Adresse à rechercher", + "Search": "Chercher", + "Driver Name:": "Nom du chauffeur:", + "Driver #:": "# Chauffeur:", + "Pickup Address:": "Lieu de prise en charge:", + "Add to Favorite Locations": "Ajoutez aux Lieux Favoris", + "Star": "Étoiles", + "Nickname:": "Pseudo", + "Add": "Ajouter", + "Your last trip": "Votre dernière course", + "Please rate your driver:": "Merci de noter votre chauffeur :", + "Comments: (optional)": "Commentaires: (optionnel)", + "Rate Trip": "Notez votre course", + "Pickup time:": "Heure de Prise en Charge :", + "Miles:": "Kilomètres :", + "Trip time:": "Temps de course :", + "Fare:": "Tarif :", + "Favorite Locations": "Lieux Favoris", + "Search Results": "Résultats", + "You have no favorite locations saved.": "Vous n’avez pas de lieux de prise en charge favoris.", + "Loading...": "Chargement...", + "Request Pickup": "Commander ici", + "Cancel Pickup": "Annuler", + "Requesting Closest Driver": "Nous demandons au chauffeur le plus proche de vous prendre en charge...", + "En Route": "Vous êtes actuellement en route...", + "Rate Last Trip": "Merci de noter votre précédent trajet pour faire une autre course.", + "Rate Before Submitting": "Merci de noter votre trajet avant de le valider.", + "Address too short": "L’adresse est trop courte", + "or did you mean": "ou vouliez-vous dire", + "Search Address Failed": "Impossible de trouver l’adresse spécifiée. Merci de saisir une autre adresse proche de l’endroit où vous vous trouvez.", + "Sending pickup request...": "Envoi de la demande de prise en charge...", + "Cancel Request Prompt": "Voulez-vous vraiment annuler votre demande ?", + "Cancel Request Arrived Prompt": 'Voulez-vous vraiment annuler votre demande ? Votre chauffeur est arrivé, vous serez donc facturé de $10 de frais d’annulation. Il pourrait être utile que vous appeliez votre chauffeur maintenant.', + "Favorite Location Nickname Length Error": "Le pseudo doit faire au moins 3 caractères de long", + "Favorite Location Save Succeeded": "Adresse enregistrée !", + "Favorite Location Save Failed": "Impossible d’enregistrer votre adresse. Merci de réessayer ultérieurement.", + "Favorite Location Title": "Adresse favorie <%= id %>", + "Search Location Title": "Recherche d’adresse <%= id %>", + "ETA Message": "Temps d’attente estimé: environ <%= minutes %> minutes", + "Nearest Cab Message": "Le chauffeur le plus proche sera là dans <%= minutes %> minute(s)", + "Arrival ETA Message": "Votre chauffeur arrivera dans <%= minutes %> minute(s)", + "Arriving Now Message": "Votre chauffeur est en approche...", + "Rating Driver Failed": "Impossible de contacter le serveur. Merci de réessayer ultérieurement ou de contacter le support si le problème persiste.", + "settings": "Paramètres", + "Information": "Information", + "Picture": "Photo", + "Change password": "Modifier votre mot de passe", + "Your current Picture": "Votre photo", + "Your Favorite Locations": "Vos lieux favoris", + "You have no favorite locations saved.": "Vous n’avez pas de lieu favori", + "Account Information": "Informations Personnelles", + "Mobile Phone Information": "Informations de Mobile", + "Change Your Password": "Changez votre mot de passe.", + "Country": "Pays", + "Language": "Langue", + "Favorite Location": "Lieu favori", + "No Approximate Address": "Impossible de trouver une adresse même approximative", + "Address:": "Adresse :", + "Information Update Succeeded": "Vos informations ont été mises à jour !", + "Information Update Failed": "Nous n’avons pas pu mettre à jour vos informations. Merci de réessayer dans quelques instants ou de contacter le support si le problème persiste.", + "Location Delete Succeeded": "Adresse supprimée !", + "Location Delete Failed": "Nous n’avons pas pu supprimée votre adresse favorie. Merci de réessayer plus tard ou de contacter le support si le problème persiste.", + "Location Edit Succeeded": "Modifications sauvegardées !", + "Location Edit Failed": "Nous n’avons pas pu sauvegarder vos modifications. Merci de réessayer dans quelques minutes.", + "Picture Update Succeeded": "Votre photo a été mise à jour !", + "Picture Update Failed": "Nous n’avons pas pu mettre à jour votre photo. Merci de réessayer dans quelques instants.", + "Personal Information": "Informations Personnelles", + "Mobile Phone Number": "Numéro de Téléphone Portable", + "Payment Information": "Informations de Facturation", + "Your card will not be charged until you take a trip.": "Votre carte ne sera pas débitée avant votre premier trajet.", + "Card Number": "Numéro de Carte", + "Promotion Code Input Label": "Code promo, code d’invitation ou “deal” acheté en ligne (optionnel)", + "Terms and Conditions": "Conditions Générales", + "HELP": "HELP", + "STOP": "STOP", + "Sign Up Agreement": "En souscrivant, j’accepte les <%= terms_link %> et <%= privacy_link %> et comprends qu’Uber est un outil de commande de chauffeur, et non un transporteur.", + "Sign Up Agreement Error": "Vous devez accepter les Conditions Générales d’utilisation d’Uber Terms and Conditions et la Politique de Confidentialité pour continuer.", + "Message and Data Rates Disclosure": "Les frais d’envoi de SMS et de consommation de données peuvent s’appliquer. Répondez <%= help_string %> au 827-222 pour obtenir de l’aide. Répondez <%= stop_string %> au 827-222 pour ne plus recevoir de SMS. Pour plus d’aide, visitez support.uber.com ou appelez le (866) 576-1039. Opérateurs supportés: AT&T, Sprint, Verizon, T-Mobile, Orange, SFR et Bouygues Telecom.", + "Zip/Postal Code": "Code Postal", + "Expiration Date": "Date D'expiration", + "Security Code": "Code de Sécurité", + "Type of Card": "Type", + "Personal": "Personnel", + "Business": "Entreprise", + "Promotion Code": "Code Promo", + "Legal Information": "Mentions Légales", + "I Agree": "J'accepte.", + "Your Trip": "Votre Course", + "Trip Info": "Informations de la Course", + "Request a fare review": "Demander un contrôle du tarif", + "Fare Review Submitted": "Votre demande de contrôle du tarif a été soumis. Nous reviendrons vers vous rapidement concernant cette demande. Nous nous excusons pour les dérangements éventuellement occasionnés !", + "Fair Price Consideration": "Nous nous engageons à proposer Uber à un tarif juste. Avant de demander un contrôle du tarif, merci de prendre en compte :", + "Your Fare Calculation": "Calcul du Prix", + "Charges": "Coûts", + "Discounts": "Réductions", + "Total Charge": "Coût total", + "Uber pricing information": "Information sur les prix d’Uber", + "Uber Pricing Information Message": "<%= learn_link %> est disponible sur notre site web.", + "GPS Point Capture Disclosure": "A cause d’un nombre limité de coordonnées GPS sauvegardées, les angles de votre trajet sur la carte peuvent apparaître coupés ou arrondis. Ces légères incohérences débouchent sur des distances mesurées plus courtes, ce qui implique toujours un prix du trajet moins élevé.", + "Fare Review Note": "Merci de nous expliquer pourquoi le tarif de cette course nécessite d’être contrôlé. Vos commentaires ci-dessous nous aideront à établir un prix plus juste si nécessaire :", + "Fare Review Error": "Il y a eu une erreur lors de l’envoi de la demande. Assurez-vous d’avoir bien ajouté une description à votre demande." + }; +}).call(this); +}, "views/clients/billing": function(exports, require, module) {(function() { + var clientsBillingTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + clientsBillingTemplate = require('templates/clients/billing'); + exports.ClientsBillingView = (function() { + __extends(ClientsBillingView, UberView); + function ClientsBillingView() { + ClientsBillingView.__super__.constructor.apply(this, arguments); + } + ClientsBillingView.prototype.id = 'billing_view'; + ClientsBillingView.prototype.className = 'view_container'; + ClientsBillingView.prototype.events = { + 'click a#add_card': 'addCard', + 'click .charge_arrear': 'chargeArrear' + }; + ClientsBillingView.prototype.render = function() { + this.RefreshUserInfo(__bind(function() { + var cards, newForm; + this.HideSpinner(); + $(this.el).html(clientsBillingTemplate()); + if (USER.payment_gateway.payment_profiles.length === 0) { + newForm = new app.views.clients.modules.creditcard; + $(this.el).find("#add_card_wrapper").html(newForm.render(0).el); + } else { + cards = new app.views.clients.modules.creditcard; + $("#cards").html(cards.render("all").el); + } + return this.delegateEvents(); + }, this)); + return this; + }; + ClientsBillingView.prototype.addCard = function(e) { + var newCard; + e.preventDefault(); + newCard = new app.views.clients.modules.creditcard; + $('#cards').append(newCard.render("new").el); + return $("a#add_card").hide(); + }; + ClientsBillingView.prototype.chargeArrear = function(e) { + var $el, arrearId, attrs, cardId, options, tryCharge; + e.preventDefault(); + $(".error_message").text(""); + $el = $(e.currentTarget); + arrearId = $el.attr('id'); + cardId = $el.parent().find('#card_to_charge').val(); + this.ShowSpinner('submit'); + tryCharge = new app.models.clientbills({ + id: arrearId + }); + attrs = { + payment_profile_id: cardId, + dataType: 'json' + }; + options = { + success: __bind(function(data, textStatus, jqXHR) { + $el.parent().find(".success_message").text(t("Billing Succeeded")); + $el.hide(); + return $el.parent().find('#card_to_charge').hide(); + }, this), + error: __bind(function(jqXHR, status, errorThrown) { + return $el.parent().find(".error_message").text(JSON.parse(status.responseText).error); + }, this), + complete: __bind(function() { + return this.HideSpinner(); + }, this) + }; + return tryCharge.save(attrs, options); + }; + return ClientsBillingView; + })(); +}).call(this); +}, "views/clients/confirm_email": function(exports, require, module) {(function() { + var clientsConfirmEmailTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + clientsConfirmEmailTemplate = require('templates/clients/confirm_email'); + exports.ClientsConfirmEmailView = (function() { + __extends(ClientsConfirmEmailView, UberView); + function ClientsConfirmEmailView() { + ClientsConfirmEmailView.__super__.constructor.apply(this, arguments); + } + ClientsConfirmEmailView.prototype.id = 'confirm_email_view'; + ClientsConfirmEmailView.prototype.className = 'view_container'; + ClientsConfirmEmailView.prototype.render = function(token) { + var attrs; + $(this.el).html(clientsConfirmEmailTemplate()); + attrs = { + data: { + email_token: token + }, + success: __bind(function(data, textStatus, jqXHR) { + var show_dashboard; + this.HideSpinner(); + show_dashboard = function() { + return app.routers.clients.navigate('!/dashboard', true); + }; + if (data.status === 'OK') { + $('.success_message').show(); + return _.delay(show_dashboard, 3000); + } else if (data.status === 'ALREADY_COMFIRMED') { + $('.already_confirmed_message').show(); + return _.delay(show_dashboard, 3000); + } else { + return $('.error_message').show(); + } + }, this), + error: __bind(function(e) { + this.HideSpinner(); + return $('.error_message').show(); + }, this), + complete: function(status) { + return $('#attempt_text').hide(); + }, + dataType: 'json', + type: 'PUT', + url: "" + API + "/users/self" + }; + $.ajax(attrs); + this.ShowSpinner('submit'); + return this; + }; + return ClientsConfirmEmailView; + })(); +}).call(this); +}, "views/clients/dashboard": function(exports, require, module) {(function() { + var clientsDashboardTemplate; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsDashboardTemplate = require('templates/clients/dashboard'); + exports.ClientsDashboardView = (function() { + var displayFirstTrip; + __extends(ClientsDashboardView, UberView); + function ClientsDashboardView() { + this.showAllTrips = __bind(this.showAllTrips, this); + this.render = __bind(this.render, this); + ClientsDashboardView.__super__.constructor.apply(this, arguments); + } + ClientsDashboardView.prototype.id = 'dashboard_view'; + ClientsDashboardView.prototype.className = 'view_container'; + ClientsDashboardView.prototype.events = { + 'click a.confirmation': 'confirmationClick', + 'click #resend_email': 'resendEmail', + 'click #resend_mobile': 'resendMobile', + 'click #show_all_trips': 'showAllTrips' + }; + ClientsDashboardView.prototype.render = function() { + var displayPage, downloadTrips; + this.HideSpinner(); + displayPage = __bind(function() { + $(this.el).html(clientsDashboardTemplate()); + this.confirmationsSetup(); + return this.RequireMaps(__bind(function() { + if (USER.trips.models[0]) { + if (!USER.trips.models[0].get("points")) { + return USER.trips.models[0].fetch({ + data: { + relationships: 'points' + }, + success: __bind(function() { + this.CacheData("USERtrips", USER.trips); + return displayFirstTrip(); + }, this) + }); + } else { + return displayFirstTrip(); + } + } + }, this)); + }, this); + downloadTrips = __bind(function() { + return this.DownloadUserTrips(displayPage, false, 10); + }, this); + this.RefreshUserInfo(downloadTrips); + return this; + }; + displayFirstTrip = __bind(function() { + var bounds, endPos, map, myOptions, path, polyline, startPos; + myOptions = { + zoom: 12, + mapTypeId: google.maps.MapTypeId.ROADMAP, + zoomControl: false, + rotateControl: false, + panControl: false, + mapTypeControl: false, + scrollwheel: false + }; + if (USER.trips.length === 10) { + $("#show_all_trips").show(); + } + if (USER.trips.length > 0) { + map = new google.maps.Map(document.getElementById("trip_details_map"), myOptions); + bounds = new google.maps.LatLngBounds(); + path = []; + _.each(USER.trips.models[0].get('points'), __bind(function(point) { + path.push(new google.maps.LatLng(point.lat, point.lng)); + return bounds.extend(_.last(path)); + }, this)); + map.fitBounds(bounds); + startPos = new google.maps.Marker({ + position: _.first(path), + map: map, + title: t('Trip started here'), + icon: 'https://uber-static.s3.amazonaws.com/marker_start.png' + }); + endPos = new google.maps.Marker({ + position: _.last(path), + map: map, + title: t('Trip ended here'), + icon: 'https://uber-static.s3.amazonaws.com/marker_end.png' + }); + polyline = new google.maps.Polyline({ + path: path, + strokeColor: '#003F87', + strokeOpacity: 1, + strokeWeight: 5 + }); + return polyline.setMap(map); + } + }, ClientsDashboardView); + ClientsDashboardView.prototype.confirmationsSetup = function() { + var blink, cardForm, element, _ref, _ref2, _ref3, _ref4, _ref5; + blink = function(element) { + var opacity; + opacity = 0.5; + if (element.css('opacity') === "0.5") { + opacity = 1.0; + } + return element.fadeTo(2000, opacity, function() { + return blink(element); + }); + }; + if (((_ref = window.USER) != null ? (_ref2 = _ref.payment_gateway) != null ? (_ref3 = _ref2.payment_profiles) != null ? _ref3.length : void 0 : void 0 : void 0) === 0) { + element = $('#confirmed_credit_card'); + cardForm = new app.views.clients.modules.creditcard; + $('#card.info').append(cardForm.render().el); + blink(element); + } + if (((_ref4 = window.USER) != null ? _ref4.confirm_email : void 0) === false) { + element = $('#confirmed_email'); + blink(element); + } + if ((((_ref5 = window.USER) != null ? _ref5.confirm_mobile : void 0) != null) === false) { + element = $('#confirmed_mobile'); + return blink(element); + } + }; + ClientsDashboardView.prototype.confirmationClick = function(e) { + e.preventDefault(); + $('.info').hide(); + $('#more_info').show(); + switch (e.currentTarget.id) { + case "card": + return $('#card.info').slideToggle(); + case "mobile": + return $('#mobile.info').slideToggle(); + case "email": + return $('#email.info').slideToggle(); + } + }; + ClientsDashboardView.prototype.resendEmail = function(e) { + var $el; + e.preventDefault(); + $el = $(e.currentTarget); + $el.removeAttr('href').prop({ + disabled: true + }); + $el.html(t("Sending Email")); + return $.ajax({ + type: 'GET', + url: API + '/users/request_confirm_email', + data: { + token: USER.token + }, + dataType: 'json', + success: __bind(function(data, textStatus, jqXHR) { + return $el.html(t("Resend Email Succeeded")); + }, this), + error: __bind(function(jqXHR, textStatus, errorThrown) { + return $el.html(t("Resend Email Failed")); + }, this) + }); + }; + ClientsDashboardView.prototype.resendMobile = function(e) { + var $el; + e.preventDefault(); + $el = $(e.currentTarget); + $el.removeAttr('href').prop({ + disabled: true + }); + $el.html("Sending message..."); + return $.ajax({ + type: 'GET', + url: API + '/users/request_confirm_mobile', + data: { + token: USER.token + }, + dataType: 'json', + success: __bind(function(data, textStatus, jqXHR) { + return $el.html(t("Resend Text Succeeded")); + }, this), + error: __bind(function(jqXHR, textStatus, errorThrown) { + return $el.html(t("Resend Text Failed")); + }, this) + }); + }; + ClientsDashboardView.prototype.showAllTrips = function(e) { + e.preventDefault(); + $(e.currentTarget).hide(); + return this.DownloadUserTrips(this.render, true, 1000); + }; + return ClientsDashboardView; + }).call(this); +}).call(this); +}, "views/clients/forgot_password": function(exports, require, module) {(function() { + var clientsForgotPasswordTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + clientsForgotPasswordTemplate = require('templates/clients/forgot_password'); + exports.ClientsForgotPasswordView = (function() { + __extends(ClientsForgotPasswordView, UberView); + function ClientsForgotPasswordView() { + ClientsForgotPasswordView.__super__.constructor.apply(this, arguments); + } + ClientsForgotPasswordView.prototype.id = 'forgotpassword_view'; + ClientsForgotPasswordView.prototype.className = 'view_container modal_view_container'; + ClientsForgotPasswordView.prototype.events = { + "submit #password_reset": "passwordReset", + "click #password_reset_submit": "passwordReset", + "submit #forgot_password": "forgotPassword", + "click #forgot_password_submit": "forgotPassword" + }; + ClientsForgotPasswordView.prototype.render = function(token) { + this.HideSpinner(); + $(this.el).html(clientsForgotPasswordTemplate({ + token: token + })); + this.delegateEvents(); + return this; + }; + ClientsForgotPasswordView.prototype.forgotPassword = function(e) { + var attrs; + e.preventDefault(); + $('.success_message').hide(); + $(".error_message").hide(); + attrs = { + data: { + login: $("#login").val() + }, + success: __bind(function(data, textStatus, jqXHR) { + this.HideSpinner(); + $('.success_message').show(); + return $("#forgot_password").hide(); + }, this), + error: __bind(function(e) { + this.HideSpinner(); + return $('.error_message').show(); + }, this), + dataType: 'json', + type: 'PUT', + url: "" + API + "/users/forgot_password" + }; + $.ajax(attrs); + return this.ShowSpinner('submit'); + }; + ClientsForgotPasswordView.prototype.passwordReset = function(e) { + var attrs; + e.preventDefault(); + attrs = { + data: { + email_token: $("#token").val(), + password: $("#password").val() + }, + success: __bind(function(data, textStatus, jqXHR) { + this.HideSpinner(); + $.cookie('token', data.token); + amplify.store('USERjson', data); + app.refreshMenu(); + return location.hash = '!/dashboard'; + }, this), + error: __bind(function(e) { + this.HideSpinner(); + return $('#error_reset').show(); + }, this), + dataType: 'json', + type: 'PUT', + url: "" + API + "/users/self" + }; + $.ajax(attrs); + return this.ShowSpinner('submit'); + }; + return ClientsForgotPasswordView; + })(); +}).call(this); +}, "views/clients/invite": function(exports, require, module) {(function() { + var clientsInviteTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsInviteTemplate = require('templates/clients/invite'); + exports.ClientsInviteView = (function() { + __extends(ClientsInviteView, UberView); + function ClientsInviteView() { + ClientsInviteView.__super__.constructor.apply(this, arguments); + } + ClientsInviteView.prototype.id = 'invite_view'; + ClientsInviteView.prototype.className = 'view_container'; + ClientsInviteView.prototype.render = function() { + this.ReadUserInfo(); + this.HideSpinner(); + $(this.el).html(clientsInviteTemplate()); + console.log(screen); + return this; + }; + return ClientsInviteView; + })(); +}).call(this); +}, "views/clients/login": function(exports, require, module) {(function() { + var clientsLoginTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsLoginTemplate = require('templates/clients/login'); + exports.ClientsLoginView = (function() { + __extends(ClientsLoginView, UberView); + function ClientsLoginView() { + ClientsLoginView.__super__.constructor.apply(this, arguments); + } + ClientsLoginView.prototype.id = 'login_view'; + ClientsLoginView.prototype.className = 'view_container modal_view_container'; + ClientsLoginView.prototype.events = { + 'submit form': 'authenticate', + 'click button': 'authenticate' + }; + ClientsLoginView.prototype.initialize = function() { + _.bindAll(this, 'render'); + return this.render(); + }; + ClientsLoginView.prototype.render = function() { + this.HideSpinner(); + $(this.el).html(clientsLoginTemplate()); + this.delegateEvents(); + return this.place(); + }; + ClientsLoginView.prototype.authenticate = function(e) { + e.preventDefault(); + return $.ajax({ + type: 'POST', + url: API + '/auth/web_login/client', + data: { + login: $("#login").val(), + password: $("#password").val() + }, + dataType: 'json', + success: function(data, textStatus, jqXHR) { + $.cookie('user', JSON.stringify(data)); + $.cookie('token', data.token); + amplify.store('USERjson', data); + $('header').html(app.views.shared.menu.render().el); + return app.routers.clients.navigate('!/dashboard', true); + }, + error: function(jqXHR, textStatus, errorThrown) { + $.cookie('user', null); + $.cookie('token', null); + if (jqXHR.status === 403) { + $.cookie('redirected_user', JSON.stringify(JSON.parse(jqXHR.responseText).error_obj), { + domain: '.uber.com' + }); + window.location = 'http://partners.uber.com/'; + } + return $('.error_message').html(JSON.parse(jqXHR.responseText).error).hide().fadeIn(); + } + }); + }; + return ClientsLoginView; + })(); +}).call(this); +}, "views/clients/modules/credit_card": function(exports, require, module) {(function() { + var creditCardTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + creditCardTemplate = require('templates/clients/modules/credit_card'); + exports.CreditCardView = (function() { + __extends(CreditCardView, UberView); + function CreditCardView() { + CreditCardView.__super__.constructor.apply(this, arguments); + } + CreditCardView.prototype.id = 'creditcard_view'; + CreditCardView.prototype.className = 'module_container'; + CreditCardView.prototype.events = { + 'submit #credit_card_form': 'processNewCard', + 'click #new_card': 'processNewCard', + 'change #card_number': 'showCardType', + 'click .edit_card_show': 'showEditCard', + 'click .edit_card': 'editCard', + 'click .delete_card': 'deleteCard', + 'click .make_default': 'makeDefault', + 'change .use_case': 'saveUseCase' + }; + CreditCardView.prototype.initialize = function() { + return app.collections.paymentprofiles.bind("refresh", __bind(function() { + return this.RefreshUserInfo(__bind(function() { + this.render("all"); + return this.HideSpinner(); + }, this)); + }, this)); + }; + CreditCardView.prototype.render = function(cards) { + if (cards == null) { + cards = "new"; + } + if (cards === "all") { + app.collections.paymentprofiles.reset(USER.payment_gateway.payment_profiles); + cards = app.collections.paymentprofiles; + } + $(this.el).html(creditCardTemplate({ + cards: cards + })); + return this; + }; + CreditCardView.prototype.processNewCard = function(e) { + var $el, attrs, model, options; + e.preventDefault(); + this.ClearGlobalStatus(); + $el = $("#credit_card_form"); + $el.find('.error_message').html(""); + attrs = { + card_number: $el.find('#card_number').val(), + card_code: $el.find('#card_code').val(), + card_expiration_month: $el.find('#card_expiration_month').val(), + card_expiration_year: $el.find('#card_expiration_year').val(), + use_case: $el.find('#use_case').val(), + "default": $el.find('#default_check').prop("checked") + }; + options = { + statusCode: { + 200: __bind(function(e) { + this.HideSpinner(); + $('#cc_form_wrapper').hide(); + app.collections.paymentprofiles.trigger("refresh"); + $(this.el).remove(); + $("a#add_card").show(); + return $('section').html(app.views.clients.billing.render().el); + }, this), + 406: __bind(function(e) { + var error, errors, _i, _len, _ref, _results; + this.HideSpinner(); + errors = JSON.parse(e.responseText); + _ref = _.keys(errors); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + error = _ref[_i]; + _results.push(error === "top_of_form" ? $("#top_of_form").html(errors[error]) : $("#credit_card_form").find("#" + error).parent().find(".error_message").html(errors[error])); + } + return _results; + }, this), + 420: __bind(function(e) { + this.HideSpinner(); + return $("#top_of_form").html(t("Unable to Verify Card")); + }, this) + } + }; + this.ShowSpinner("submit"); + model = new app.models.paymentprofile; + model.save(attrs, options); + return app.collections.paymentprofiles.add(model); + }; + CreditCardView.prototype.showCardType = function(e) { + var $el, reAmerica, reDiscover, reMaster, reVisa, validCard; + reVisa = /^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/; + reMaster = /^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/; + reAmerica = /^6011-?\d{4}-?\d{4}-?\d{4}$/; + reDiscover = /^3[4,7]\d{13}$/; + $el = $("#card_logos"); + validCard = false; + if (e.currentTarget.value.match(reVisa)) { + validCard = true; + } else if (e.currentTarget.value.match(reMaster)) { + $el.css('background-position', "-60px"); + validCard = true; + } else if (e.currentTarget.value.match(reAmerica)) { + $el.css('background-position', "-120px"); + validCard = true; + } else if (e.currentTarget.value.match(reDiscover)) { + $el.css('background-position', "-180px"); + validCard = true; + } + if (validCard) { + $el.css('width', "60px"); + return $el.css('margin-left', "180px"); + } else { + $el.css('width', "250px"); + return $el.css('margin-left', "80px"); + } + }; + CreditCardView.prototype.showEditCard = function(e) { + var $el, id; + e.preventDefault(); + $el = $(e.currentTarget); + if ($el.html() === t("Edit")) { + id = $el.html(t("Cancel")).parents("tr").attr("id").substring(1); + return $("#e" + id).show(); + } else { + id = $el.html(t("Edit")).parents("tr").attr("id").substring(1); + return $("#e" + id).hide(); + } + }; + CreditCardView.prototype.editCard = function(e) { + var $el, attrs, id, options; + e.preventDefault(); + this.ClearGlobalStatus(); + $el = $(e.currentTarget).parents("td"); + id = $el.parents("tr").attr("id").substring(1); + $el.attr('disabled', 'disabled'); + this.ShowSpinner('submit'); + attrs = { + card_expiration_month: $el.find('#card_expiration_month').val(), + card_expiration_year: $el.find('#card_expiration_year').val(), + card_code: $el.find('#card_code').val() + }; + options = { + success: __bind(function(response) { + this.HideSpinner(); + this.ShowSuccess(t("Credit Card Update Succeeded")); + $("#e" + id).hide(); + $("#d" + id).find(".edit_card_show").html(t("Edit")); + return app.collections.paymentprofiles.trigger("refresh"); + }, this), + error: __bind(function(e) { + this.HideSpinner(); + this.ShowError(t("Credit Card Update Failed")); + return $el.removeAttr('disabled'); + }, this) + }; + app.collections.paymentprofiles.models[id].set(attrs); + return app.collections.paymentprofiles.models[id].save({}, options); + }; + CreditCardView.prototype.deleteCard = function(e) { + var $el, id, options; + e.preventDefault(); + $el = $(e.currentTarget).parents("td"); + id = $el.parents("tr").attr("id").substring(1); + this.ClearGlobalStatus(); + this.ShowSpinner('submit'); + options = { + success: __bind(function(response) { + this.ShowSuccess(t("Credit Card Delete Succeeded")); + $("form").hide(); + app.collections.paymentprofiles.trigger("refresh"); + return $('section').html(app.views.clients.billing.render().el); + }, this), + error: __bind(function(xhr, e) { + this.HideSpinner(); + return this.ShowError(t("Credit Card Delete Failed")); + }, this) + }; + return app.collections.paymentprofiles.models[id].destroy(options); + }; + CreditCardView.prototype.saveUseCase = function(e) { + var $el, attrs, id, options, use_case; + this.ClearGlobalStatus(); + $el = $(e.currentTarget); + use_case = $el.val(); + id = $el.parents("tr").attr("id").substring(1); + attrs = { + use_case: use_case + }; + options = { + success: __bind(function(response) { + return this.ShowSuccess(t("Credit Card Update Category Succeeded")); + }, this), + error: __bind(function(e) { + return this.ShowError(t("Credit Card Update Category Failed")); + }, this) + }; + app.collections.paymentprofiles.models[id].set(attrs); + return app.collections.paymentprofiles.models[id].save({}, options); + }; + CreditCardView.prototype.makeDefault = function(e) { + var $el, attrs, id, options; + e.preventDefault(); + this.ClearGlobalStatus(); + $el = $(e.currentTarget).parents("td"); + id = $el.parents("tr").attr("id").substring(1); + attrs = { + "default": true + }; + options = { + success: __bind(function(response) { + this.ShowSuccess(t("Credit Card Update Default Succeeded")); + return app.collections.paymentprofiles.trigger("refresh"); + }, this), + error: __bind(function(e) { + return this.ShowError(t("Credit Card Update Default Failed")); + }, this) + }; + app.collections.paymentprofiles.models[id].set(attrs); + return app.collections.paymentprofiles.models[id].save({}, options); + }; + return CreditCardView; + })(); +}).call(this); +}, "views/clients/promotions": function(exports, require, module) {(function() { + var clientsPromotionsTemplate; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsPromotionsTemplate = require('templates/clients/promotions'); + exports.ClientsPromotionsView = (function() { + __extends(ClientsPromotionsView, UberView); + function ClientsPromotionsView() { + this.render = __bind(this.render, this); + ClientsPromotionsView.__super__.constructor.apply(this, arguments); + } + ClientsPromotionsView.prototype.id = 'promotions_view'; + ClientsPromotionsView.prototype.className = 'view_container'; + ClientsPromotionsView.prototype.events = { + 'submit form': 'submitPromo', + 'click button': 'submitPromo' + }; + ClientsPromotionsView.prototype.initialize = function() { + if (this.model) { + return this.RefreshUserInfo(this.render); + } + }; + ClientsPromotionsView.prototype.render = function() { + var renderTemplate; + this.ReadUserInfo(); + renderTemplate = __bind(function() { + $(this.el).html(clientsPromotionsTemplate({ + promos: window.USER.unexpired_client_promotions || [] + })); + return this.HideSpinner(); + }, this); + this.DownloadUserPromotions(renderTemplate); + return this; + }; + ClientsPromotionsView.prototype.submitPromo = function(e) { + var attrs, model, options, refreshTable; + e.preventDefault(); + this.ClearGlobalStatus(); + refreshTable = __bind(function() { + $('section').html(this.render().el); + return this.HideSpinner(); + }, this); + attrs = { + code: $('#code').val() + }; + options = { + success: __bind(function(response) { + this.HideSpinner(); + if (response.get('first_name')) { + return this.ShowSuccess("Your promotion has been applied in the form of an account credit. Click here to check your balance."); + } else { + this.ShowSuccess("Your promotion has successfully been applied"); + return this.RefreshUserInfo(this.render, true); + } + }, this), + statusCode: { + 400: __bind(function(e) { + this.ShowError(JSON.parse(e.responseText).error); + return this.HideSpinner(); + }, this) + } + }; + this.ShowSpinner("submit"); + model = new app.models.promotions; + return model.save(attrs, options); + }; + return ClientsPromotionsView; + })(); +}).call(this); +}, "views/clients/request": function(exports, require, module) {(function() { + var clientsRequestTemplate; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsRequestTemplate = require('templates/clients/request'); + exports.ClientsRequestView = (function() { + __extends(ClientsRequestView, UberView); + function ClientsRequestView() { + this.AjaxCall = __bind(this.AjaxCall, this); + this.AskDispatch = __bind(this.AskDispatch, this); + this.removeMarkers = __bind(this.removeMarkers, this); + this.displaySearchLoc = __bind(this.displaySearchLoc, this); + this.displayFavLoc = __bind(this.displayFavLoc, this); + this.showFavLoc = __bind(this.showFavLoc, this); + this.addToFavLoc = __bind(this.addToFavLoc, this); + this.removeCabs = __bind(this.removeCabs, this); + this.requestRide = __bind(this.requestRide, this); + this.rateTrip = __bind(this.rateTrip, this); + this.locationChange = __bind(this.locationChange, this); + this.panToLocation = __bind(this.panToLocation, this); + this.clickLocation = __bind(this.clickLocation, this); + this.searchLocation = __bind(this.searchLocation, this); + this.mouseoutLocation = __bind(this.mouseoutLocation, this); + this.mouseoverLocation = __bind(this.mouseoverLocation, this); + this.fetchTripDetails = __bind(this.fetchTripDetails, this); + this.submitRating = __bind(this.submitRating, this); + this.setStatus = __bind(this.setStatus, this); + this.initialize = __bind(this.initialize, this); + ClientsRequestView.__super__.constructor.apply(this, arguments); + } + ClientsRequestView.prototype.id = 'request_view'; + ClientsRequestView.prototype.className = 'view_container'; + ClientsRequestView.prototype.pollInterval = 2 * 1000; + ClientsRequestView.prototype.events = { + "submit #search_form": "searchAddress", + "click .locations_link": "locationLinkHandle", + "mouseover .location_row": "mouseoverLocation", + "mouseout .location_row": "mouseoutLocation", + "click .location_row": "clickLocation", + "click #search_location": "searchLocation", + "click #pickupHandle": "pickupHandle", + "click .stars": "rateTrip", + "submit #rating_form": "submitRating", + "click #addToFavButton": "showFavLoc", + "click #favLocNickname": "selectInputText", + "submit #favLoc_form": "addToFavLoc" + }; + ClientsRequestView.prototype.status = ""; + ClientsRequestView.prototype.pickupMarker = "https://uber-static.s3.amazonaws.com/pickup_marker.png"; + ClientsRequestView.prototype.cabMarker = "https://uber-static.s3.amazonaws.com/cab_marker.png"; + ClientsRequestView.prototype.initialize = function() { + var displayCabs; + displayCabs = __bind(function() { + return this.AskDispatch("NearestCab"); + }, this); + this.showCabs = _.throttle(displayCabs, this.pollInterval); + return this.numSearchToDisplay = 1; + }; + ClientsRequestView.prototype.setStatus = function(status) { + var autocomplete; + if (this.status === status) { + return; + } + try { + google.maps.event.trigger(this.map, 'resize'); + } catch (_e) {} + switch (status) { + case "init": + this.AskDispatch("StatusClient"); + this.status = "init"; + return this.ShowSpinner("load"); + case "ready": + this.HideSpinner(); + $(".panel").hide(); + $("#top_bar").fadeIn(); + $("#location_panel").fadeIn(); + $("#location_panel_control").fadeIn(); + $("#pickupHandle").attr("class", "button_green").fadeIn().find("span").html(t("Request Pickup")); + this.pickup_icon.setDraggable(true); + this.map.panTo(this.pickup_icon.getPosition()); + this.showCabs(); + try { + this.pickup_icon.setMap(this.map); + this.displayFavLoc(); + autocomplete = new google.maps.places.Autocomplete(document.getElementById('address'), { + types: ['geocode'] + }); + autocomplete.bindTo('bounds', this.map); + } catch (_e) {} + return this.status = "ready"; + case "searching": + this.HideSpinner(); + this.removeMarkers(); + $(".panel").hide(); + $("#top_bar").fadeOut(); + $("#status_message").html(t("Requesting Closest Driver")); + $("#pickupHandle").attr("class", "button_red").fadeIn().find("span").html(t("Cancel Pickup")); + this.pickup_icon.setDraggable(false); + this.pickup_icon.setMap(this.map); + return this.status = "searching"; + case "waiting": + this.HideSpinner(); + this.removeMarkers(); + $(".panel").hide(); + $("#top_bar").fadeOut(); + $("#pickupHandle").attr("class", "button_red").fadeIn().find("span").html(t("Cancel Pickup")); + $("#waiting_riding").fadeIn(); + this.pickup_icon.setDraggable(false); + this.pickup_icon.setMap(this.map); + return this.status = "waiting"; + case "arriving": + this.HideSpinner(); + this.removeMarkers(); + $(".panel").hide(); + $("#top_bar").fadeOut(); + $("#pickupHandle").attr("class", "button_red").fadeIn().find("span").html(t("Cancel Pickup")); + $("#waiting_riding").fadeIn(); + this.pickup_icon.setDraggable(false); + this.pickup_icon.setMap(this.map); + return this.status = "arriving"; + case "riding": + this.HideSpinner(); + this.removeMarkers(); + $(".panel").hide(); + $("#top_bar").fadeOut(); + $("#pickupHandle").fadeIn().attr("class", "button_red").find("span").html(t("Cancel Pickup")); + $("#waiting_riding").fadeIn(); + this.pickup_icon.setDraggable(false); + this.status = "riding"; + return $("#status_message").html(t("En Route")); + case "rate": + this.HideSpinner(); + $(".panel").hide(); + $("#pickupHandle").fadeOut(); + $("#trip_completed_panel").fadeIn(); + $('#status_message').html(t("Rate Last Trip")); + return this.status = "rate"; + } + }; + ClientsRequestView.prototype.render = function() { + this.ReadUserInfo(); + this.HideSpinner(); + this.ShowSpinner("load"); + $(this.el).html(clientsRequestTemplate()); + this.cabs = []; + this.RequireMaps(__bind(function() { + var center, myOptions, streetViewPano; + center = new google.maps.LatLng(37.7749295, -122.4194155); + this.markers = []; + this.pickup_icon = new google.maps.Marker({ + position: center, + draggable: true, + clickable: true, + icon: this.pickupMarker + }); + this.geocoder = new google.maps.Geocoder(); + myOptions = { + zoom: 12, + center: center, + mapTypeId: google.maps.MapTypeId.ROADMAP, + rotateControl: false, + rotateControl: false, + panControl: false + }; + this.map = new google.maps.Map($(this.el).find("#map_wrapper_right")[0], myOptions); + if (this.status === "ready") { + this.pickup_icon.setMap(this.map); + } + if (geo_position_js.init()) { + geo_position_js.getCurrentPosition(__bind(function(data) { + var location; + location = new google.maps.LatLng(data.coords.latitude, data.coords.longitude); + this.pickup_icon.setPosition(location); + this.map.panTo(location); + return this.map.setZoom(16); + }, this)); + } + this.setStatus("init"); + streetViewPano = this.map.getStreetView(); + google.maps.event.addListener(streetViewPano, 'visible_changed', __bind(function() { + if (streetViewPano.getVisible()) { + this.pickupMarker = "https://uber-static.s3.amazonaws.com/pickup_marker_large.png"; + this.cabMarker = "https://uber-static.s3.amazonaws.com/cab_marker_large.png"; + } else { + this.pickupMarker = "https://uber-static.s3.amazonaws.com/pickup_marker.png"; + this.cabMarker = "https://uber-static.s3.amazonaws.com/cab_marker.png"; + } + this.pickup_icon.setIcon(this.pickupMarker); + return _.each(this.cabs, __bind(function(cab) { + return cab.setIcon(this.cabMarker); + }, this)); + }, this)); + if (this.status === "ready") { + return this.displayFavLoc(); + } + }, this)); + return this; + }; + ClientsRequestView.prototype.submitRating = function(e) { + var $el, message, rating; + e.preventDefault(); + $el = $(e.currentTarget); + rating = 0; + _(5).times(function(num) { + if ($el.find(".stars#" + (num + 1)).attr("src") === "/web/img/star_active.png") { + return rating = num + 1; + } + }); + if (rating === 0) { + $("#status_message").html("").html(t("Rate Before Submitting")); + } else { + this.ShowSpinner("submit"); + this.AskDispatch("RatingDriver", { + rating: rating + }); + } + message = $el.find("#comments").val().toString(); + if (message.length > 5) { + return this.AskDispatch("Feedback", { + message: message + }); + } + }; + ClientsRequestView.prototype.fetchTripDetails = function(id) { + var trip; + trip = new app.models.trip({ + id: id + }); + return trip.fetch({ + data: { + relationships: 'points,driver,city' + }, + dataType: 'json', + success: __bind(function() { + var bounds, endPos, path, polyline, startPos; + bounds = new google.maps.LatLngBounds(); + path = []; + _.each(trip.get('points'), __bind(function(point) { + path.push(new google.maps.LatLng(point.lat, point.lng)); + return bounds.extend(_.last(path)); + }, this)); + startPos = new google.maps.Marker({ + position: _.first(path), + map: this.map, + title: t("Trip started here"), + icon: 'https://uber-static.s3.amazonaws.com/carstart.png' + }); + endPos = new google.maps.Marker({ + position: _.last(path), + map: this.map, + title: t("Trip ended here"), + icon: 'https://uber-static.s3.amazonaws.com/carstop.png' + }); + polyline = new google.maps.Polyline({ + path: path, + strokeColor: '#003F87', + strokeOpacity: 1, + strokeWeight: 5 + }); + polyline.setMap(this.map); + this.map.fitBounds(bounds); + $("#tripTime").html(app.helpers.parseDateTime(trip.get('pickup_local_time'), trip.get('city.timezone'))); + $("#tripDist").html(app.helpers.RoundNumber(trip.get('distance'), 2)); + $("#tripDur").html(app.helpers.FormatSeconds(trip.get('duration'))); + return $("#tripFare").html(app.helpers.FormatCurrency(trip.get('fare'))); + }, this) + }); + }; + ClientsRequestView.prototype.searchAddress = function(e) { + var $locationsDiv, address, alphabet, bounds, showResults; + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + try { + e.preventDefault(); + } catch (_e) {} + $('.error_message').html(""); + $locationsDiv = $("
"); + address = $('#address').val(); + bounds = new google.maps.LatLngBounds(); + if (address.length < 5) { + $('#status_message').html(t("Address too short")).fadeIn(); + return false; + } + showResults = __bind(function(address, index) { + var first_cell, row, second_cell; + if (index < this.numSearchToDisplay) { + first_cell = "
" + address.formatted_address + "
" + (t('or did you mean')) + "
" + address.formatted_address + "
+ + + +
Rod VaggGitHub/rvaggTwitter/@rvagg
Benjamin ByholmGitHub/kkoopa
Trevor NorrisGitHub/trevnorrisTwitter/@trevnorris
+ +Licence & copyright +----------------------- + +Copyright (c) 2013 Rod Vagg & NAN contributors (listed above). + +Native Abstractions for Node.js is licensed under an MIT +no-false-attribs license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details. diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/nan.h b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/nan.h new file mode 100644 index 00000000..b3eb02db --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/nan.h @@ -0,0 +1,884 @@ +/********************************************************************************** + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2013 NAN contributors: + * - Rod Vagg + * - Benjamin Byholm + * - Trevor Norris + * + * MIT +no-false-attribs License + * + * Version 0.3.2 (current Node unstable: 0.11.6, Node stable: 0.10.17) + * + * ChangeLog: + * * 0.3.2 Aug 30 2013 + * - Fix missing scope declaration in GetFromPersistent() and SaveToPersistent + * in NanAsyncWorker + * + * * 0.3.1 Aug 20 2013 + * - fix "not all control paths return a value" compile warning on some platforms + * + * * 0.3.0 Aug 19 2013 + * - Made NAN work with NPM + * - Lots of fixes to NanFromV8String, pulling in features from new Node core + * - Changed node::encoding to Nan::Encoding in NanFromV8String to unify the API + * - Added optional error number argument for NanThrowError() + * - Added NanInitPersistent() + * - Added NanReturnNull() and NanReturnEmptyString() + * - Added NanLocker and NanUnlocker + * - Added missing scopes + * - Made sure to clear disposed Persistent handles + * - Changed NanAsyncWorker to allocate error messages on the heap + * - Changed NanThrowError(Local) to NanThrowError(Handle) + * - Fixed leak in NanAsyncWorker when errmsg is used + * + * * 0.2.2 Aug 5 2013 + * - Fixed usage of undefined variable with node::BASE64 in NanFromV8String() + * + * * 0.2.1 Aug 5 2013 + * - Fixed 0.8 breakage, node::BUFFER encoding type not available in 0.8 for + * NanFromV8String() + * + * * 0.2.0 Aug 5 2013 + * - Added NAN_PROPERTY_GETTER, NAN_PROPERTY_SETTER, NAN_PROPERTY_ENUMERATOR, + * NAN_PROPERTY_DELETER, NAN_PROPERTY_QUERY + * - Extracted _NAN_METHOD_ARGS, _NAN_GETTER_ARGS, _NAN_SETTER_ARGS, + * _NAN_PROPERTY_GETTER_ARGS, _NAN_PROPERTY_SETTER_ARGS, + * _NAN_PROPERTY_ENUMERATOR_ARGS, _NAN_PROPERTY_DELETER_ARGS, + * _NAN_PROPERTY_QUERY_ARGS + * - Added NanGetInternalFieldPointer, NanSetInternalFieldPointer + * - Added NAN_WEAK_CALLBACK, NAN_WEAK_CALLBACK_OBJECT, + * NAN_WEAK_CALLBACK_DATA, NanMakeWeak + * - Renamed THROW_ERROR to _NAN_THROW_ERROR + * - Added NanNewBufferHandle(char*, size_t, node::smalloc::FreeCallback, void*) + * - Added NanBufferUse(char*, uint32_t) + * - Added NanNewContextHandle(v8::ExtensionConfiguration*, + * v8::Handle, v8::Handle) + * - Fixed broken NanCallback#GetFunction() + * - Added optional encoding and size arguments to NanFromV8String() + * - Added NanGetPointerSafe() and NanSetPointerSafe() + * - Added initial test suite (to be expanded) + * - Allow NanUInt32OptionValue to convert any Number object + * + * * 0.1.0 Jul 21 2013 + * - Added `NAN_GETTER`, `NAN_SETTER` + * - Added `NanThrowError` with single Local argument + * - Added `NanNewBufferHandle` with single uint32_t argument + * - Added `NanHasInstance(Persistent&, Handle)` + * - Added `Local NanCallback#GetFunction()` + * - Added `NanCallback#Call(int, Local[])` + * - Deprecated `NanCallback#Run(int, Local[])` in favour of Call + * + * See https://github.com/rvagg/nan for the latest update to this file + **********************************************************************************/ + +#ifndef NAN_H +#define NAN_H + +#include +#include +#include + +// some generic helpers + +template static inline bool NanSetPointerSafe(T *var, T val) { + if (var) { + *var = val; + return true; + } else { + return false; + } +} + +template static inline T NanGetPointerSafe( + T *var, + T fallback = reinterpret_cast(0)) { + if (var) { + return *var; + } else { + return fallback; + } +} + +#define NanSymbol(value) v8::String::NewSymbol(value) + +static inline bool NanBooleanOptionValue( + v8::Local optionsObj + , v8::Handle opt, bool def) { + + if (def) { + return optionsObj.IsEmpty() + || !optionsObj->Has(opt) + || optionsObj->Get(opt)->BooleanValue(); + } else { + return !optionsObj.IsEmpty() + && optionsObj->Has(opt) + && optionsObj->Get(opt)->BooleanValue(); + } +} + +static inline bool NanBooleanOptionValue( + v8::Local optionsObj + , v8::Handle opt) { + return NanBooleanOptionValue(optionsObj, opt, false); +} + +static inline uint32_t NanUInt32OptionValue( + v8::Local optionsObj + , v8::Handle opt + , uint32_t def) { + + return !optionsObj.IsEmpty() + && optionsObj->Has(opt) + && optionsObj->Get(opt)->IsNumber() + ? optionsObj->Get(opt)->Uint32Value() + : def; +} + +#if (NODE_MODULE_VERSION > 0x000B) +// Node 0.11+ (0.11.3 and below won't compile with these) + +static v8::Isolate* nan_isolate = v8::Isolate::GetCurrent(); + +# define _NAN_METHOD_ARGS const v8::FunctionCallbackInfo& args +# define NAN_METHOD(name) void name(_NAN_METHOD_ARGS) +# define _NAN_GETTER_ARGS const v8::PropertyCallbackInfo& args +# define NAN_GETTER(name) \ + void name(v8::Local property, _NAN_GETTER_ARGS) +# define _NAN_SETTER_ARGS const v8::PropertyCallbackInfo& args +# define NAN_SETTER(name) \ + void name( \ + v8::Local property \ + , v8::Local value \ + , _NAN_SETTER_ARGS) +# define _NAN_PROPERTY_GETTER_ARGS \ + const v8::PropertyCallbackInfo& args +# define NAN_PROPERTY_GETTER(name) \ + void name(v8::Local property \ + , _NAN_PROPERTY_GETTER_ARGS) +# define _NAN_PROPERTY_SETTER_ARGS \ + const v8::PropertyCallbackInfo& args +# define NAN_PROPERTY_SETTER(name) \ + void name(v8::Local property \ + , v8::Local value \ + , _NAN_PROPERTY_SETTER_ARGS) +# define _NAN_PROPERTY_ENUMERATOR_ARGS \ + const v8::PropertyCallbackInfo& args +# define NAN_PROPERTY_ENUMERATOR(name) \ + void name(_NAN_PROPERTY_ENUMERATOR_ARGS) +# define _NAN_PROPERTY_DELETER_ARGS \ + const v8::PropertyCallbackInfo& args +# define NAN_PROPERTY_DELETER(name) \ + void name( \ + v8::Local property \ + , _NAN_PROPERTY_DELETER_ARGS) +# define _NAN_PROPERTY_QUERY_ARGS \ + const v8::PropertyCallbackInfo& args +# define NAN_PROPERTY_QUERY(name) \ + void name(v8::Local property, _NAN_PROPERTY_QUERY_ARGS) +# define NanGetInternalFieldPointer(object, index) \ + object->GetAlignedPointerFromInternalField(index) +# define NanSetInternalFieldPointer(object, index, value) \ + object->SetAlignedPointerInInternalField(index, value) + +# define NAN_WEAK_CALLBACK(type, name) \ + void name( \ + v8::Isolate* isolate, \ + v8::Persistent* object, \ + type data) +# define NAN_WEAK_CALLBACK_OBJECT (*object) +# define NAN_WEAK_CALLBACK_DATA(type) ((type) data) + +# define NanScope() v8::HandleScope scope(nan_isolate) +# define NanLocker() v8::Locker locker(nan_isolate) +# define NanUnlocker() v8::Unlocker unlocker(nan_isolate) +# define NanReturnValue(value) return args.GetReturnValue().Set(value) +# define NanReturnUndefined() return +# define NanReturnNull() return args.GetReturnValue().SetNull() +# define NanReturnEmptyString() return args.GetReturnValue().SetEmptyString() +# define NanAssignPersistent(type, handle, obj) handle.Reset(nan_isolate, obj) +# define NanInitPersistent(type, name, obj) \ + v8::Persistent name(nan_isolate, obj) +# define NanObjectWrapHandle(obj) obj->handle() +# define NanMakeWeak(handle, parameter, callback) \ + handle.MakeWeak(nan_isolate, parameter, callback) + +# define _NAN_THROW_ERROR(fun, errmsg) \ + do { \ + NanScope(); \ + v8::ThrowException(fun(v8::String::New(errmsg))); \ + } while (0); + + inline static void NanThrowError(const char* errmsg) { + _NAN_THROW_ERROR(v8::Exception::Error, errmsg); + } + + inline static void NanThrowError(v8::Handle error) { + NanScope(); + v8::ThrowException(error); + } + + inline static void NanThrowError(const char *msg, const int errorNumber) { + v8::Local err = v8::Exception::Error(v8::String::New(msg)); + v8::Local obj = err.As(); + obj->Set(v8::String::New("code"), v8::Int32::New(errorNumber)); + NanThrowError(err); + } + + inline static void NanThrowTypeError(const char* errmsg) { + _NAN_THROW_ERROR(v8::Exception::TypeError, errmsg); + } + + inline static void NanThrowRangeError(const char* errmsg) { + _NAN_THROW_ERROR(v8::Exception::RangeError, errmsg); + } + + template static inline void NanDispose(v8::Persistent &handle) { + handle.Dispose(nan_isolate); + handle.Clear(); + } + + static inline v8::Local NanNewBufferHandle ( + char *data, + size_t length, + node::smalloc::FreeCallback callback, + void *hint) { + return node::Buffer::New(data, length, callback, hint); + } + + static inline v8::Local NanNewBufferHandle ( + char *data, uint32_t size) { + return node::Buffer::New(data, size); + } + + static inline v8::Local NanNewBufferHandle (uint32_t size) { + return node::Buffer::New(size); + } + + static inline v8::Local NanBufferUse(char* data, uint32_t size) { + return node::Buffer::Use(data, size); + } + + template + inline v8::Local NanPersistentToLocal( + const v8::Persistent& persistent) { + if (persistent.IsWeak()) { + return v8::Local::New(nan_isolate, persistent); + } else { + return *reinterpret_cast*>( + const_cast*>(&persistent)); + } + } + + inline bool NanHasInstance( + v8::Persistent& function_template + , v8::Handle value) { + return NanPersistentToLocal(function_template)->HasInstance(value); + } + + static inline v8::Local NanNewContextHandle( + v8::ExtensionConfiguration* extensions = NULL, + v8::Handle tmpl = v8::Handle(), + v8::Handle obj = v8::Handle()) { + return v8::Local::New(nan_isolate, v8::Context::New( + nan_isolate, extensions, tmpl, obj)); + } + +#else +// Node 0.8 and 0.10 + +# define _NAN_METHOD_ARGS const v8::Arguments& args +# define NAN_METHOD(name) v8::Handle name(_NAN_METHOD_ARGS) +# define _NAN_GETTER_ARGS const v8::AccessorInfo &args +# define NAN_GETTER(name) \ + v8::Handle name(v8::Local property, _NAN_GETTER_ARGS) +# define _NAN_SETTER_ARGS const v8::AccessorInfo &args +# define NAN_SETTER(name) \ + void name( \ + v8::Local property \ + , v8::Local value \ + , _NAN_SETTER_ARGS) +# define _NAN_PROPERTY_GETTER_ARGS const v8::AccessorInfo& args +# define NAN_PROPERTY_GETTER(name) \ + v8::Handle name(v8::Local property \ + , _NAN_PROPERTY_GETTER_ARGS) +# define _NAN_PROPERTY_SETTER_ARGS const v8::AccessorInfo& args +# define NAN_PROPERTY_SETTER(name) \ + v8::Handle name(v8::Local property \ + , v8::Local value \ + , _NAN_PROPERTY_SETTER_ARGS) +# define _NAN_PROPERTY_ENUMERATOR_ARGS const v8::AccessorInfo& args +# define NAN_PROPERTY_ENUMERATOR(name) \ + v8::Handle name(_NAN_PROPERTY_ENUMERATOR_ARGS) +# define _NAN_PROPERTY_DELETER_ARGS const v8::AccessorInfo& args +# define NAN_PROPERTY_DELETER(name) \ + v8::Handle name( \ + v8::Local property \ + , _NAN_PROPERTY_DELETER_ARGS) +# define _NAN_PROPERTY_QUERY_ARGS const v8::AccessorInfo& args +# define NAN_PROPERTY_QUERY(name) \ + v8::Handle name( \ + v8::Local property \ + , _NAN_PROPERTY_QUERY_ARGS) + +# define NanGetInternalFieldPointer(object, index) \ + object->GetPointerFromInternalField(index) +# define NanSetInternalFieldPointer(object, index, value) \ + object->SetPointerInInternalField(index, value) +# define NAN_WEAK_CALLBACK(type, name) void name( \ + v8::Persistent object, \ + void *data) +# define NAN_WEAK_CALLBACK_OBJECT object +# define NAN_WEAK_CALLBACK_DATA(type) ((type) data) + +# define NanScope() v8::HandleScope scope +# define NanLocker() v8::Locker locker +# define NanUnlocker() v8::Unlocker unlocker +# define NanReturnValue(value) return scope.Close(value) +# define NanReturnUndefined() return v8::Undefined() +# define NanReturnNull() return v8::Null() +# define NanReturnEmptyString() return v8::String::Empty() +# define NanInitPersistent(type, name, obj) \ + v8::Persistent name = v8::Persistent::New(obj) +# define NanAssignPersistent(type, handle, obj) \ + handle = v8::Persistent::New(obj) +# define NanObjectWrapHandle(obj) obj->handle_ +# define NanMakeWeak(handle, parameters, callback) \ + handle.MakeWeak(parameters, callback) + +# define _NAN_THROW_ERROR(fun, errmsg) \ + do { \ + NanScope(); \ + return v8::ThrowException(fun(v8::String::New(errmsg))); \ + } while (0); + + inline static v8::Handle NanThrowError(const char* errmsg) { + _NAN_THROW_ERROR(v8::Exception::Error, errmsg); + } + + inline static v8::Handle NanThrowError( + v8::Handle error) { + NanScope(); + return v8::ThrowException(error); + } + + inline static v8::Handle NanThrowError( + const char *msg, + const int errorNumber) { + v8::Local err = v8::Exception::Error(v8::String::New(msg)); + v8::Local obj = err.As(); + obj->Set(v8::String::New("code"), v8::Int32::New(errorNumber)); + return NanThrowError(err); + } + + inline static v8::Handle NanThrowTypeError(const char* errmsg) { + _NAN_THROW_ERROR(v8::Exception::TypeError, errmsg); + } + + inline static v8::Handle NanThrowRangeError(const char* errmsg) { + _NAN_THROW_ERROR(v8::Exception::RangeError, errmsg); + } + + template static inline void NanDispose(v8::Persistent &handle) { + handle.Dispose(); + handle.Clear(); + } + + static inline v8::Local NanNewBufferHandle ( + char *data, + size_t length, + node::Buffer::free_callback callback, + void *hint) { + return v8::Local::New( + node::Buffer::New(data, length, callback, hint)->handle_); + } + + static inline v8::Local NanNewBufferHandle ( + char *data, uint32_t size) { + return v8::Local::New(node::Buffer::New(data, size)->handle_); + } + + static inline v8::Local NanNewBufferHandle (uint32_t size) { + return v8::Local::New(node::Buffer::New(size)->handle_); + } + + static inline void FreeData(char *data, void *hint) { + delete[] data; + } + + static inline v8::Local NanBufferUse(char* data, uint32_t size) { + return v8::Local::New( + node::Buffer::New(data, size, FreeData, NULL)->handle_); + } + + template + inline v8::Local NanPersistentToLocal( + const v8::Persistent& persistent) { + if (persistent.IsWeak()) { + return v8::Local::New(persistent); + } else { + return *reinterpret_cast*>( + const_cast*>(&persistent)); + } + } + + inline bool NanHasInstance( + v8::Persistent& function_template + , v8::Handle value) { + return function_template->HasInstance(value); + } + + static inline v8::Local NanNewContextHandle( + v8::ExtensionConfiguration* extensions = NULL + , v8::Handle tmpl = + v8::Handle() + , v8::Handle obj = v8::Handle() + ) { + v8::Persistent ctx = + v8::Context::New(extensions, tmpl, obj); + v8::Local lctx = v8::Local::New(ctx); + ctx.Dispose(); + return lctx; + } + +#endif // node version + +class NanCallback { + public: + NanCallback(const v8::Local &fn) { + NanScope(); + v8::Local obj = v8::Object::New(); + obj->Set(NanSymbol("callback"), fn); + NanAssignPersistent(v8::Object, handle, obj); + } + + ~NanCallback() { + if (handle.IsEmpty()) return; + handle.Dispose(); + handle.Clear(); + } + + inline v8::Local GetFunction () { + return NanPersistentToLocal(handle)->Get(NanSymbol("callback")) + .As(); + } + + // deprecated + void Run(int argc, v8::Local argv[]) { + Call(argc, argv); + } + + void Call(int argc, v8::Local argv[]) { + NanScope(); + + v8::Local callback = NanPersistentToLocal(handle)-> + Get(NanSymbol("callback")).As(); + v8::TryCatch try_catch; + callback->Call(v8::Context::GetCurrent()->Global(), argc, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } + + private: + v8::Persistent handle; +}; + +/* abstract */ class NanAsyncWorker { +public: + NanAsyncWorker (NanCallback *callback) : callback(callback) { + request.data = this; + errmsg = NULL; + } + + virtual ~NanAsyncWorker () { + NanScope(); + + if (!persistentHandle.IsEmpty()) + NanDispose(persistentHandle); + if (callback) + delete callback; + if (errmsg) + delete errmsg; + } + + virtual void WorkComplete () { + NanScope(); + + if (errmsg == NULL) + HandleOKCallback(); + else + HandleErrorCallback(); + delete callback; + callback = NULL; + } + + virtual void Execute () =0; + + uv_work_t request; + +protected: + v8::Persistent persistentHandle; + NanCallback *callback; + const char *errmsg; + + void SavePersistent(const char *key, v8::Local &obj) { + NanScope(); + + v8::Local handle = NanPersistentToLocal(persistentHandle); + handle->Set(NanSymbol(key), obj); + } + + v8::Local GetFromPersistent(const char *key) { + NanScope(); + + v8::Local handle = NanPersistentToLocal(persistentHandle); + return handle->Get(NanSymbol(key)).As(); + } + + virtual void HandleOKCallback () { + NanScope(); + + callback->Call(0, NULL); + }; + + virtual void HandleErrorCallback () { + NanScope(); + + v8::Local argv[] = { + v8::Exception::Error(v8::String::New(errmsg)) + }; + callback->Call(1, argv); + } +}; + +inline void NanAsyncExecute (uv_work_t* req) { + NanAsyncWorker *worker = static_cast(req->data); + worker->Execute(); +} + +inline void NanAsyncExecuteComplete (uv_work_t* req) { + NanAsyncWorker* worker = static_cast(req->data); + worker->WorkComplete(); + delete worker; +} + +inline void NanAsyncQueueWorker (NanAsyncWorker* worker) { + uv_queue_work( + uv_default_loop() + , &worker->request + , NanAsyncExecute + , (uv_after_work_cb)NanAsyncExecuteComplete + ); +} + +//// Base 64 //// + +#define _nan_base64_encoded_size(size) ((size + 2 - ((size + 2) % 3)) / 3 * 4) + + +// Doesn't check for padding at the end. Can be 1-2 bytes over. +static inline size_t _nan_base64_decoded_size_fast(size_t size) { + size_t remainder = size % 4; + + size = (size / 4) * 3; + if (remainder) { + if (size == 0 && remainder == 1) { + // special case: 1-byte input cannot be decoded + size = 0; + } else { + // non-padded input, add 1 or 2 extra bytes + size += 1 + (remainder == 3); + } + } + + return size; +} + +template +static size_t _nan_base64_decoded_size(const TypeName* src, size_t size) { + if (size == 0) + return 0; + + if (src[size - 1] == '=') + size--; + if (size > 0 && src[size - 1] == '=') + size--; + + return _nan_base64_decoded_size_fast(size); +} + + +// supports regular and URL-safe base64 +static const int _nan_unbase64_table[] = + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + +#define _nan_unbase64(x) _nan_unbase64_table[(uint8_t)(x)] + + +template +static size_t _nan_base64_decode(char* buf, + size_t len, + const TypeName* src, + const size_t srcLen) { + char a, b, c, d; + char* dst = buf; + char* dstEnd = buf + len; + const TypeName* srcEnd = src + srcLen; + + while (src < srcEnd && dst < dstEnd) { + int remaining = srcEnd - src; + + while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining == 0 || *src == '=') break; + a = _nan_unbase64(*src++); + + while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining <= 1 || *src == '=') break; + b = _nan_unbase64(*src++); + + *dst++ = (a << 2) | ((b & 0x30) >> 4); + if (dst == dstEnd) break; + + while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining <= 2 || *src == '=') break; + c = _nan_unbase64(*src++); + + *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2); + if (dst == dstEnd) break; + + while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining <= 3 || *src == '=') break; + d = _nan_unbase64(*src++); + + *dst++ = ((c & 0x03) << 6) | (d & 0x3F); + } + + return dst - buf; +} + +//// HEX //// + +template +unsigned _nan_hex2bin(TypeName c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); + if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); + return static_cast(-1); +} + + +template +static size_t _nan_hex_decode(char* buf, + size_t len, + const TypeName* src, + const size_t srcLen) { + size_t i; + for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) { + unsigned a = _nan_hex2bin(src[i * 2 + 0]); + unsigned b = _nan_hex2bin(src[i * 2 + 1]); + if (!~a || !~b) return i; + buf[i] = a * 16 + b; + } + + return i; +} + +static bool _NanGetExternalParts( + v8::Handle val + , const char** data + , size_t* len) { + + if (node::Buffer::HasInstance(val)) { + *data = node::Buffer::Data(val.As()); + *len = node::Buffer::Length(val.As()); + return true; + + } + + assert(val->IsString()); + v8::Local str = v8::Local::New(val.As()); + + if (str->IsExternalAscii()) { + const v8::String::ExternalAsciiStringResource* ext; + ext = str->GetExternalAsciiStringResource(); + *data = ext->data(); + *len = ext->length(); + return true; + + } else if (str->IsExternal()) { + const v8::String::ExternalStringResource* ext; + ext = str->GetExternalStringResource(); + *data = reinterpret_cast(ext->data()); + *len = ext->length(); + return true; + } + + return false; +} + +namespace Nan { + enum Encoding {ASCII, UTF8, BASE64, UCS2, BINARY, HEX, BUFFER}; +} + +static inline char* NanFromV8String( + v8::Handle from + , enum Nan::Encoding encoding = Nan::UTF8 + , size_t *datalen = NULL + , char *buf = NULL + , size_t buflen = 0 + , int flags = v8::String::NO_NULL_TERMINATION + | v8::String::HINT_MANY_WRITES_EXPECTED) { + + NanScope(); + + size_t sz_; + size_t term_len = !(flags & v8::String::NO_NULL_TERMINATION); + char *data = NULL; + size_t len; + bool is_extern = _NanGetExternalParts( + from + , const_cast(&data) + , &len); + + if (is_extern && !term_len) { + NanSetPointerSafe(datalen, len); + return data; + } + + v8::Local toStr = from->ToString(); + + char *to = buf; + + v8::String::AsciiValue value(toStr); + switch(encoding) { + case Nan::ASCII: +#if NODE_MODULE_VERSION < 0x0C + sz_ = toStr->Length(); + if (to == NULL) { + to = new char[sz_ + term_len]; + } else { + assert(buflen >= sz_ + term_len && "too small buffer"); + } + NanSetPointerSafe( + datalen + , toStr->WriteAscii(to, 0, sz_ + term_len, flags)); + return to; +#endif + case Nan::BINARY: + case Nan::BUFFER: + sz_ = toStr->Length(); + if (to == NULL) { + to = new char[sz_ + term_len]; + } else { + assert(buflen >= sz_ + term_len && "too small buffer"); + } +#if NODE_MODULE_VERSION < 0x0C + // TODO(isaacs): THIS IS AWFUL!!! + // AGREE(kkoopa) + { + uint16_t* twobytebuf = new uint16_t[sz_ + term_len]; + + size_t len = toStr->Write(twobytebuf, 0, sz_ + term_len, flags); + + for (size_t i = 0; i < sz_ + term_len && i < len + term_len; i++) { + unsigned char *b = reinterpret_cast(&twobytebuf[i]); + to[i] = *b; + } + + NanSetPointerSafe(datalen, len); + + delete[] twobytebuf; + return to; + } +#else + NanSetPointerSafe( + datalen, + toStr->WriteOneByte( + reinterpret_cast(to) + , 0 + , sz_ + term_len + , flags)); + return to; +#endif + case Nan::UTF8: + sz_ = toStr->Utf8Length(); + if (to == NULL) { + to = new char[sz_ + term_len]; + } else { + assert(buflen >= sz_ + term_len && "too small buffer"); + } + NanSetPointerSafe( + datalen + , toStr->WriteUtf8(to, sz_ + term_len, NULL, flags) - term_len); + return to; + case Nan::BASE64: + sz_ = _nan_base64_decoded_size(*value, toStr->Length()); + if (to == NULL) { + to = new char[sz_ + term_len]; + } else { + assert(buflen >= sz_ + term_len); + } + NanSetPointerSafe( + datalen + , _nan_base64_decode(to, sz_, *value, value.length())); + if (term_len) { + to[sz_] = '\0'; + } + return to; + case Nan::UCS2: + { + sz_ = toStr->Length(); + if (to == NULL) { + to = new char[(sz_ + term_len) * 2]; + } else { + assert(buflen >= (sz_ + term_len) * 2 && "too small buffer"); + } + + int bc = 2 * toStr->Write( + reinterpret_cast(to) + , 0 + , sz_ + term_len + , flags); + NanSetPointerSafe(datalen, bc); + return to; + } + case Nan::HEX: + sz_ = toStr->Length(); + assert(!(sz_ & 1) && "bad hex data"); + if (to == NULL) { + to = new char[sz_ / 2 + term_len]; + } else { + assert(buflen >= sz_ / 2 + term_len && "too small buffer"); + } + + NanSetPointerSafe( + datalen + , _nan_hex_decode(to, sz_ / 2, *value, value.length())); + if (term_len) { + to[sz_ / 2] = '\0'; + } + return to; + default: + assert(0 && "unknown encoding"); + } + return to; +} + +#endif diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/package.json new file mode 100644 index 00000000..34ba61a9 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/nan/package.json @@ -0,0 +1,36 @@ +{ + "name": "nan", + "version": "0.3.2", + "description": "Native Abstractions for Node.js: C++ header for Node 0.8->0.12 compatibility", + "main": ".index.js", + "repository": { + "type": "git", + "url": "git://github.com/rvagg/nan.git" + }, + "contributors": [ + { + "name": "Rod Vagg", + "email": "r@va.gg", + "url": "https://github.com/rvagg" + }, + { + "name": "Benjamin Byholm", + "email": "bbyholm@abo.fi", + "url": "https://github.com/kkoopa/" + }, + { + "name": "Trevor Norris", + "email": "trev.norris@gmail.com", + "url": "https://github.com/trevnorris" + } + ], + "license": "MIT", + "readme": "Native Abstractions for Node.js\n===============================\n\n**A header file filled with macro and utility goodness for making addon development for Node.js easier across versions 0.8, 0.10 and 0.11, and eventually 0.12.**\n\n***Current version: 0.3.2*** *(See [nan.h](https://github.com/rvagg/nan/blob/master/nan.h) for changelog)*\n\n[![NPM](https://nodei.co/npm/nan.png?downloads=true&stars=true)](https://nodei.co/npm/nan/) [![NPM](https://nodei.co/npm-dl/nan.png?months=6)](https://nodei.co/npm/nan/)\n\nThanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.11/0.12, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js addons without having to inspect `NODE_MODULE_VERSION` and get yourself into a macro-tangle.\n\nThis project also contains some helper utilities that make addon development a bit more pleasant.\n\n * **[Usage](#usage)**\n * **[Example](#example)**\n * **[API](#api)**\n\n\n## Usage\n\nSimply add **NAN** as a dependency in the *package.json* of your Node addon:\n\n```js\n\"dependencies\": {\n ...\n \"nan\" : \"~0.3.1\"\n ...\n}\n```\n\nPull in the path to **NAN** in your *binding.gyp* so that you can use `#include \"nan.h\"` in your *.cpp*:\n\n```js\n\"include_dirs\" : [\n ...\n \"` when compiling your addon.\n\n\n## Example\n\nSee **[LevelDOWN](https://github.com/rvagg/node-leveldown/pull/48)** for a full example of **NAN** in use.\n\nFor a simpler example, see the **[async pi estimation example](https://github.com/rvagg/nan/tree/master/examples/async_pi_estimate)** in the examples directory for full code and an explanation of what this Monte Carlo Pi estimation example does. Below are just some parts of the full example that illustrate the use of **NAN**.\n\nCompare to the current 0.10 version of this example, found in the [node-addon-examples](https://github.com/rvagg/node-addon-examples/tree/master/9_async_work) repository and also a 0.11 version of the same found [here](https://github.com/kkoopa/node-addon-examples/tree/5c01f58fc993377a567812597e54a83af69686d7/9_async_work).\n\nNote that there is no embedded version sniffing going on here and also the async work is made much simpler, see below for details on the `NanAsyncWorker` class.\n\n```c++\n// addon.cc\n#include \n#include \"nan.h\"\n// ...\n\nusing namespace v8;\n\nvoid InitAll(Handle exports) {\n exports->Set(NanSymbol(\"calculateSync\"),\n FunctionTemplate::New(CalculateSync)->GetFunction());\n\n exports->Set(NanSymbol(\"calculateAsync\"),\n FunctionTemplate::New(CalculateAsync)->GetFunction());\n}\n\nNODE_MODULE(addon, InitAll)\n```\n\n```c++\n// sync.h\n#include \n#include \"nan.h\"\n\nNAN_METHOD(CalculateSync);\n```\n\n```c++\n// sync.cc\n#include \n#include \"nan.h\"\n#include \"sync.h\"\n// ...\n\nusing namespace v8;\n\n// Simple synchronous access to the `Estimate()` function\nNAN_METHOD(CalculateSync) {\n NanScope();\n\n // expect a number as the first argument\n int points = args[0]->Uint32Value();\n double est = Estimate(points);\n\n NanReturnValue(Number::New(est));\n}\n```\n\n```c++\n// async.cc\n#include \n#include \"nan.h\"\n#include \"async.h\"\n\n// ...\n\nusing namespace v8;\n\nclass PiWorker : public NanAsyncWorker {\n public:\n PiWorker(NanCallback *callback, int points)\n : NanAsyncWorker(callback), points(points) {}\n ~PiWorker() {}\n\n // Executed inside the worker-thread.\n // It is not safe to access V8, or V8 data structures\n // here, so everything we need for input and output\n // should go on `this`.\n void Execute () {\n estimate = Estimate(points);\n }\n\n // Executed when the async work is complete\n // this function will be run inside the main event loop\n // so it is safe to use V8 again\n void HandleOKCallback () {\n NanScope();\n\n Local argv[] = {\n Local::New(Null())\n , Number::New(estimate)\n };\n\n callback->Call(2, argv);\n };\n\n private:\n int points;\n double estimate;\n};\n\n// Asynchronous access to the `Estimate()` function\nNAN_METHOD(CalculateAsync) {\n NanScope();\n\n int points = args[0]->Uint32Value();\n NanCallback *callback = new NanCallback(args[1].As());\n\n NanAsyncQueueWorker(new PiWorker(callback, points));\n NanReturnUndefined();\n}\n```\n\n\n## API\n\n * NAN_METHOD\n * NAN_GETTER\n * NAN_SETTER\n * NAN_PROPERTY_GETTER\n * NAN_PROPERTY_SETTER\n * NAN_PROPERTY_ENUMERATOR\n * NAN_PROPERTY_DELETER\n * NAN_PROPERTY_QUERY\n * NAN_WEAK_CALLBACK\n * NanReturnValue\n * NanReturnUndefined\n * NanReturnNull\n * NanReturnEmptyString\n * NanScope\n * NanLocker\n * NanUnlocker\n * NanGetInternalFieldPointer\n * NanSetInternalFieldPointer\n * NanObjectWrapHandle\n * NanMakeWeak\n * NanSymbol\n * NanGetPointerSafe\n * NanSetPointerSafe\n * NanFromV8String\n * NanBooleanOptionValue\n * NanUInt32OptionValue\n * NanThrowError, NanThrowTypeError, NanThrowRangeError, NanThrowError(Handle), NanThrowError(Handle, int)\n * NanNewBufferHandle(char *, size_t, FreeCallback, void *), NanNewBufferHandle(char *, uint32_t), NanNewBufferHandle(uint32_t)\n * NanBufferUse(char *, uint32_t)\n * NanNewContextHandle\n * NanHasInstance\n * NanPersistentToLocal\n * NanDispose\n * NanAssignPersistent\n * NanInitPersistent\n * NanCallback\n * NanAsyncWorker\n * NanAsyncQueueWorker\n\n\n### NAN_METHOD(methodname)\n\nUse `NAN_METHOD` to define your V8 accessible methods:\n\n```c++\n// .h:\nclass Foo : public node::ObjectWrap {\n ...\n\n static NAN_METHOD(Bar);\n static NAN_METHOD(Baz);\n}\n\n\n// .cc:\nNAN_METHOD(Foo::Bar) {\n ...\n}\n\nNAN_METHOD(Foo::Baz) {\n ...\n}\n```\n\nThe reason for this macro is because of the method signature change in 0.11:\n\n```c++\n// 0.10 and below:\nHandle name(const Arguments& args)\n\n// 0.11 and above\nvoid name(const FunctionCallbackInfo& args)\n```\n\nThe introduction of `FunctionCallbackInfo` brings additional complications:\n\n\n### NAN_GETTER(methodname)\n\nUse `NAN_GETTER` to declare your V8 accessible getters. You get a `Local` `property` and an appropriately typed `args` object that can act like the `args` argument to a `NAN_METHOD` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_GETTER`.\n\n\n### NAN_SETTER(methodname)\n\nUse `NAN_SETTER` to declare your V8 accessible setters. Same as `NAN_GETTER` but you also get a `Local` `value` object to work with.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_SETTER`.\n\n\n### NAN_PROPERTY_GETTER(cbname)\nUse `NAN_PROPERTY_GETTER` to declare your V8 accessible property getters. You get a `Local` `property` and an appropriately typed `args` object that can act similar to the `args` argument to a `NAN_METHOD` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_GETTER`.\n\n\n### NAN_PROPERTY_SETTER(cbname)\nUse `NAN_PROPERTY_SETTER` to declare your V8 accessible property setters. Same as `NAN_PROPERTY_GETTER` but you also get a `Local` `value` object to work with.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_SETTER`.\n\n\n### NAN_PROPERTY_ENUMERATOR(cbname)\nUse `NAN_PROPERTY_ENUMERATOR` to declare your V8 accessible property enumerators. You get an appropriately typed `args` object like the `args` argument to a `NAN_PROPERTY_GETTER` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_ENUMERATOR`.\n\n\n### NAN_PROPERTY_DELETER(cbname)\nUse `NAN_PROPERTY_DELETER` to declare your V8 accessible property deleters. Same as `NAN_PROPERTY_GETTER`.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_DELETER`.\n\n\n### NAN_PROPERTY_QUERY(cbname)\nUse `NAN_PROPERTY_QUERY` to declare your V8 accessible property queries. Same as `NAN_PROPERTY_GETTER`.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_QUERY`.\n\n\n### NAN_WEAK_CALLBACK(type, cbname)\n\nUse `NAN_WEAK_CALLBACK` to declare your V8 WeakReference callbacks. There is an object argument accessible through `NAN_WEAK_CALLBACK_OBJECT`. The `type` argument gives the type of the `data` argument, accessible through `NAN_WEAK_CALLBACK_DATA(type)`.\n\n```c++\nstatic NAN_WEAK_CALLBACK(BufferReference*, WeakCheck) {\n if (NAN_WEAK_CALLBACK_DATA(BufferReference*)->noLongerNeeded_) {\n delete NAN_WEAK_CALLBACK_DATA(BufferReference*);\n } else {\n // Still in use, revive, prevent GC\n NanMakeWeak(NAN_WEAK_CALLBACK_OBJECT, NAN_WEAK_CALLBACK_DATA(BufferReference*), &WeakCheck);\n }\n}\n\n```\n\n### NanReturnValue(Handle<Value>)\n\nUse `NanReturnValue` when you want to return a value from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Bar) {\n ...\n\n NanReturnValue(String::New(\"FooBar!\"));\n}\n```\n\nNo `return` statement required.\n\n\n### NanReturnUndefined()\n\nUse `NanReturnUndefined` when you don't want to return anything from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnUndefined();\n}\n```\n\n\n### NanReturnNull()\n\nUse `NanReturnNull` when you want to return `Null` from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnNull();\n}\n```\n\n\n### NanReturnEmptyString()\n\nUse `NanReturnEmptyString` when you want to return an empty `String` from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnEmptyString();\n}\n```\n\n\n### NanScope()\n\nThe introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanScope()` necessary, use it in place of `HandleScope scope`:\n\n```c++\nNAN_METHOD(Foo::Bar) {\n NanScope();\n\n NanReturnValue(String::New(\"FooBar!\"));\n}\n```\n\n\n### NanLocker()\n\nThe introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanLocker()` necessary, use it in place of `Locker locker`:\n\n```c++\nNAN_METHOD(Foo::Bar) {\n NanLocker();\n ...\n NanUnlocker();\n}\n```\n\n\n### NanUnlocker()\n\nThe introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanUnlocker()` necessary, use it in place of `Unlocker unlocker`:\n\n```c++\nNAN_METHOD(Foo::Bar) {\n NanLocker();\n ...\n NanUnlocker();\n}\n```\n\n\n### void * NanGetInternalFieldPointer(Handle<Object>, int)\n\nGets a pointer to the internal field with at `index` from a V8 `Object` handle.\n\n```c++\nLocal obj;\n...\nNanGetInternalFieldPointer(obj, 0);\n```\n\n### void NanSetInternalFieldPointer(Handle<Object>, int, void *)\n\nSets the value of the internal field at `index` on a V8 `Object` handle.\n\n```c++\nstatic Persistent dataWrapperCtor;\n...\nLocal wrapper = NanPersistentToLocal(dataWrapperCtor)->NewInstance();\nNanSetInternalFieldPointer(wrapper, 0, this);\n```\n\n\n### Local<Object> NanObjectWrapHandle(Object)\n\nWhen you want to fetch the V8 object handle from a native object you've wrapped with Node's `ObjectWrap`, you should use `NanObjectWrapHandle`:\n\n```c++\nNanObjectWrapHandle(iterator)->Get(String::NewSymbol(\"end\"))\n```\n\n\n### NanMakeWeak(Persistent<T>, parameter, callback)\n\nMake a persistent reference weak.\n\n\n### String NanSymbol(char *)\n\nThis isn't strictly about compatibility, it's just an easier way to create string symbol objects (i.e. `String::NewSymbol(x)`), for getting and setting object properties, or names of objects.\n\n```c++\nbool foo = false;\nif (obj->Has(NanSymbol(\"foo\")))\n foo = optionsObj->Get(NanSymbol(\"foo\"))->BooleanValue()\n```\n\n\n### Type NanGetPointerSafe(Type *[, Type])\n\nA helper for getting values from optional pointers. If the pointer is `NULL`, the function returns the optional default value, which defaults to `0`. Otherwise, the function returns the value the pointer points to.\n\n```c++\nchar *plugh(uint32_t *optional) {\n char res[] = \"xyzzy\";\n uint32_t param = NanGetPointerSafe(optional, 0x1337);\n switch (param) {\n ...\n }\n NanSetPointerSafe(optional, 0xDEADBEEF);\n} \n```\n\n\n### bool NanSetPointerSafe(Type *, Type)\n\nA helper for setting optional argument pointers. If the pointer is `NULL`, the function simply return `false`. Otherwise, the value is assigned to the variable the pointer points to.\n\n```c++\nconst char *plugh(size_t *outputsize) {\n char res[] = \"xyzzy\";\n if !(NanSetPointerSafe(outputsize, strlen(res) + 1)) {\n ...\n }\n\n ...\n}\n```\n\n\n### char* NanFromV8String(Handle<Value>[, enum Nan::Encoding, size_t *, char *, size_t, int])\n\nWhen you want to convert a V8 `String` to a `char*` use `NanFromV8String`. It is possible to define an encoding that defaults to `Nan::UTF8` as well as a pointer to a variable that will be assigned the number of bytes in the returned string. It is also possible to supply a buffer and its length to the function in order not to have a new buffer allocated. The final argument allows optionally setting `String::WriteOptions`, which default to `String::HINT_MANY_WRITES_EXPECTED | String::NO_NULL_TERMINATION`.\nJust remember that you'll end up with an object that you'll need to `delete[]` at some point unless you supply your own buffer:\n\n```c++\nsize_t count;\nchar* name = NanFromV8String(args[0]);\nchar* decoded = NanFromV8String(args[1], Nan::BASE64, &count, NULL, 0, String::HINT_MANY_WRITES_EXPECTED);\nchar param_copy[count];\nmemcpy(param_copy, decoded, count);\ndelete[] decoded;\n```\n\n\n### bool NanBooleanOptionValue(Handle<Value>, Handle<String>[, bool])\n\nWhen you have an \"options\" object that you need to fetch properties from, boolean options can be fetched with this pair. They check first if the object exists (`IsEmpty`), then if the object has the given property (`Has`) then they get and convert/coerce the property to a `bool`.\n\nThe optional last parameter is the *default* value, which is `false` if left off:\n\n```c++\n// `foo` is false unless the user supplies a truthy value for it\nbool foo = NanBooleanOptionValue(optionsObj, NanSymbol(\"foo\"));\n// `bar` is true unless the user supplies a falsy value for it\nbool bar = NanBooleanOptionValueDefTrue(optionsObj, NanSymbol(\"bar\"), true);\n```\n\n\n### uint32_t NanUInt32OptionValue(Handle<Value>, Handle<String>, uint32_t)\n\nSimilar to `NanBooleanOptionValue`, use `NanUInt32OptionValue` to fetch an integer option from your options object. Can be any kind of JavaScript `Number` and it will be coerced to an unsigned 32-bit integer.\n\nRequires all 3 arguments as a default is not optional:\n\n```c++\nuint32_t count = NanUInt32OptionValue(optionsObj, NanSymbol(\"count\"), 1024);\n```\n\n\n### NanThrowError(message), NanThrowTypeError(message), NanThrowRangeError(message), NanThrowError(Local<Value>), NanThrowError(Local<Value>, int)\n\nFor throwing `Error`, `TypeError` and `RangeError` objects. You should `return` this call:\n\n```c++\nreturn NanThrowError(\"you must supply a callback argument\");\n```\n\nCan also handle any custom object you may want to throw. If used with the error code argument, it will add the supplied error code to the error object as a property called `code`.\n\n\n### Local<Object> NanNewBufferHandle(char *, uint32_t), Local<Object> NanNewBufferHandle(uint32_t)\n\nThe `Buffer` API has changed a little in Node 0.11, this helper provides consistent access to `Buffer` creation:\n\n```c++\nNanNewBufferHandle((char*)value.data(), value.size());\n```\n\nCan also be used to initialize a `Buffer` with just a `size` argument.\n\nCan also be supplied with a `NAN_WEAK_CALLBACK` and a hint for the garbage collector, when dealing with weak references.\n\n\n### Local<Object> NanBufferUse(char*, uint32_t)\n\n`Buffer::New(char*, uint32_t)` prior to 0.11 would make a copy of the data.\nWhile it was possible to get around this, it required a shim by passing a\ncallback. So the new API `Buffer::Use(char*, uint32_t)` was introduced to remove\nneeding to use this shim.\n\n`NanBufferUse` uses the `char*` passed as the backing data, and will free the\nmemory automatically when the weak callback is called. Keep this in mind, as\ncareless use can lead to \"double free or corruption\" and other cryptic failures.\n\n\n### bool NanHasInstance(Persistent<FunctionTemplate>&, Handle<Value>)\n\nCan be used to check the type of an object to determine it is of a particular class you have already defined and have a `Persistent` handle for.\n\n\n### Local<Type> NanPersistentToLocal(Persistent<Type>&)\n\nAside from `FunctionCallbackInfo`, the biggest and most painful change to V8 in Node 0.11 is the many restrictions now placed on `Persistent` handles. They are difficult to assign and difficult to fetch the original value out of.\n\nUse `NanPersistentToLocal` to convert a `Persistent` handle back to a `Local` handle.\n\n```c++\nLocal handle = NanPersistentToLocal(persistentHandle);\n```\n\n\n### Local<Context> NanNewContextHandle([ExtensionConfiguration*, Handle<ObjectTemplate>, Handle<Value>])\nCreates a new `Local` handle.\n\n```c++\nLocal ftmpl = FunctionTemplate::New();\nLocal otmpl = ftmpl->InstanceTemplate();\nLocal ctx = NanNewContextHandle(NULL, otmpl);\n```\n\n\n### void NanDispose(Persistent<T> &)\n\nUse `NanDispose` to dispose a `Persistent` handle.\n\n```c++\nNanDispose(persistentHandle);\n```\n\n\n### NanAssignPersistent(type, handle, object)\n\nUse `NanAssignPersistent` to assign a non-`Persistent` handle to a `Persistent` one. You can no longer just declare a `Persistent` handle and assign directly to it later, you have to `Reset` it in Node 0.11, so this makes it easier.\n\nIn general it is now better to place anything you want to protect from V8's garbage collector as properties of a generic `Object` and then assign that to a `Persistent`. This works in older versions of Node also if you use `NanAssignPersistent`:\n\n```c++\nPersistent persistentHandle;\n\n...\n\nLocal obj = Object::New();\nobj->Set(NanSymbol(\"key\"), keyHandle); // where keyHandle might be a Local\nNanAssignPersistent(Object, persistentHandle, obj)\n```\n\n\n### NanInitPersistent(type, name, object)\n\nUser `NanInitPersistent` to declare and initialize a new `Persistent` with the supplied object. The assignment operator for `Persistent` is no longer public in Node 0.11, so this macro makes it easier to declare and initializing a new `Persistent`. See NanAssignPersistent for more information.\n\n```c++\nLocal obj = Object::New();\nobj->Set(NanSymbol(\"key\"), keyHandle); // where keyHandle might be a Local\nNanInitPersistent(Object, persistentHandle, obj);\n```\n\n\n### NanCallback\n\nBecause of the difficulties imposed by the changes to `Persistent` handles in V8 in Node 0.11, creating `Persistent` versions of your `Local` handles is annoyingly tricky. `NanCallback` makes it easier by taking your `Local` handle, making it persistent until the `NanCallback` is deleted and even providing a handy `Call()` method to fetch and execute the callback `Function`.\n\n```c++\nLocal callbackHandle = callback = args[0].As();\nNanCallback *callback = new NanCallback(callbackHandle);\n// pass `callback` around and it's safe from GC until you:\ndelete callback;\n```\n\nYou can execute the callback like so:\n\n```c++\n// no arguments:\ncallback->Call(0, NULL);\n\n// an error argument:\nLocal argv[] = {\n Exception::Error(String::New(\"fail!\"))\n};\ncallback->Call(1, argv);\n\n// a success argument:\nLocal argv[] = {\n Local::New(Null()),\n String::New(\"w00t!\")\n};\ncallback->Call(2, argv);\n```\n\n`NanCallback` also has a `Local GetCallback()` method that you can use to fetch a local handle to the underlying callback function if you need it.\n\n\n### NanAsyncWorker\n\n`NanAsyncWorker` is an abstract class that you can subclass to have much of the annoying async queuing and handling taken care of for you. It can even store arbitrary V8 objects for you and have them persist while the async work is in progress.\n\nSee a rough outline of the implementation:\n\n```c++\nclass NanAsyncWorker {\npublic:\n NanAsyncWorker (NanCallback *callback);\n\n // Clean up persistent handles and delete the *callback\n virtual ~NanAsyncWorker ();\n\n // Check the `char *errmsg` property and call HandleOKCallback()\n // or HandleErrorCallback depending on whether it has been set or not\n virtual void WorkComplete ();\n\n // You must implement this to do some async work. If there is an\n // error then allocate `errmsg` to to a message and the callback will\n // be passed that string in an Error object\n virtual void Execute ();\n\nprotected:\n // Set this if there is an error, otherwise it's NULL\n const char *errmsg;\n\n // Save a V8 object in a Persistent handle to protect it from GC\n void SavePersistent(const char *key, Local &obj);\n\n // Fetch a stored V8 object (don't call from within `Execute()`)\n Local GetFromPersistent(const char *key);\n\n // Default implementation calls the callback function with no arguments.\n // Override this to return meaningful data\n virtual void HandleOKCallback ();\n\n // Default implementation calls the callback function with an Error object\n // wrapping the `errmsg` string\n virtual void HandleErrorCallback ();\n};\n```\n\n\n### NanAsyncQueueWorker(NanAsyncWorker *)\n\n`NanAsyncQueueWorker` will run a `NanAsyncWorker` asynchronously via libuv. Both the *execute* and *after_work* steps are taken care of for you—most of the logic for this is embedded in `NanAsyncWorker`.\n\n### Contributors\n\nNAN is only possible due to the excellent work of the following contributors:\n\n\n\n\n\n
Rod VaggGitHub/rvaggTwitter/@rvagg
Benjamin ByholmGitHub/kkoopa
Trevor NorrisGitHub/trevnorrisTwitter/@trevnorris
\n\nLicence & copyright\n-----------------------\n\nCopyright (c) 2013 Rod Vagg & NAN contributors (listed above).\n\nNative Abstractions for Node.js is licensed under an MIT +no-false-attribs license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/rvagg/nan/issues" + }, + "homepage": "https://github.com/rvagg/nan", + "_id": "nan@0.3.2", + "_from": "nan@~0.3.0" +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/.npmignore b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/.npmignore new file mode 100644 index 00000000..6bfffbb7 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/.npmignore @@ -0,0 +1,5 @@ +npm-debug.log +node_modules +.*.swp +.lock-* +build/ diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/Makefile b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/Makefile new file mode 100644 index 00000000..7496b6fc --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/Makefile @@ -0,0 +1,12 @@ +ALL_TESTS = $(shell find test/ -name '*.test.js') + +run-tests: + @./node_modules/.bin/mocha \ + -t 2000 \ + $(TESTFLAGS) \ + $(TESTS) + +test: + @$(MAKE) NODE_PATH=lib TESTS="$(ALL_TESTS)" run-tests + +.PHONY: test diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/README.md b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/README.md new file mode 100644 index 00000000..4b39a2a7 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/README.md @@ -0,0 +1,28 @@ +# options.js # + +A very light-weight in-code option parsers for node.js. + +## License ## + +(The MIT License) + +Copyright (c) 2012 Einar Otto Stangvik <einaros@gmail.com> + +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: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +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. diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/lib/options.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/lib/options.js new file mode 100644 index 00000000..4fc45e90 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/lib/options.js @@ -0,0 +1,86 @@ +/*! + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var fs = require('fs'); + +function Options(defaults) { + var internalValues = {}; + var values = this.value = {}; + Object.keys(defaults).forEach(function(key) { + internalValues[key] = defaults[key]; + Object.defineProperty(values, key, { + get: function() { return internalValues[key]; }, + configurable: false, + enumerable: true + }); + }); + this.reset = function() { + Object.keys(defaults).forEach(function(key) { + internalValues[key] = defaults[key]; + }); + return this; + }; + this.merge = function(options, required) { + options = options || {}; + if (Object.prototype.toString.call(required) === '[object Array]') { + var missing = []; + for (var i = 0, l = required.length; i < l; ++i) { + var key = required[i]; + if (!(key in options)) { + missing.push(key); + } + } + if (missing.length > 0) { + if (missing.length > 1) { + throw new Error('options ' + + missing.slice(0, missing.length - 1).join(', ') + ' and ' + + missing[missing.length - 1] + ' must be defined'); + } + else throw new Error('option ' + missing[0] + ' must be defined'); + } + } + Object.keys(options).forEach(function(key) { + if (key in internalValues) { + internalValues[key] = options[key]; + } + }); + return this; + }; + this.copy = function(keys) { + var obj = {}; + Object.keys(defaults).forEach(function(key) { + if (keys.indexOf(key) !== -1) { + obj[key] = values[key]; + } + }); + return obj; + }; + this.read = function(filename, cb) { + if (typeof cb == 'function') { + var self = this; + fs.readFile(filename, function(error, data) { + if (error) return cb(error); + var conf = JSON.parse(data); + self.merge(conf); + cb(); + }); + } + else { + var conf = JSON.parse(fs.readFileSync(filename)); + this.merge(conf); + } + return this; + }; + this.isDefined = function(key) { + return typeof values[key] != 'undefined'; + }; + this.isDefinedAndNonNull = function(key) { + return typeof values[key] != 'undefined' && values[key] !== null; + }; + Object.freeze(values); + Object.freeze(this); +} + +module.exports = Options; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/package.json new file mode 100644 index 00000000..cbdc5c21 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/package.json @@ -0,0 +1,33 @@ +{ + "author": { + "name": "Einar Otto Stangvik", + "email": "einaros@gmail.com", + "url": "http://2x.io" + }, + "name": "options", + "description": "A very light-weight in-code option parsers for node.js.", + "version": "0.0.5", + "repository": { + "type": "git", + "url": "git://github.com/einaros/options.js.git" + }, + "main": "lib/options", + "scripts": { + "test": "make test" + }, + "engines": { + "node": ">=0.4.0" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "latest" + }, + "readme": "# options.js #\n\nA very light-weight in-code option parsers for node.js.\n\n## License ##\n\n(The MIT License)\n\nCopyright (c) 2012 Einar Otto Stangvik <einaros@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/einaros/options.js/issues" + }, + "homepage": "https://github.com/einaros/options.js", + "_id": "options@0.0.5", + "_from": "options@>=0.0.5" +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/test/fixtures/test.conf b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/test/fixtures/test.conf new file mode 100644 index 00000000..6e624441 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/test/fixtures/test.conf @@ -0,0 +1,4 @@ +{ + "a": "foobar", + "b": false +} \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/test/options.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/test/options.test.js new file mode 100644 index 00000000..6a1d9f5b --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/test/options.test.js @@ -0,0 +1,140 @@ +var Options = require('options') + , assert = require('assert'); + +describe('Options', function() { + describe('#ctor', function() { + it('initializes options', function() { + var option = new Options({a: true, b: false}); + assert.strictEqual(true, option.value.a); + assert.strictEqual(false, option.value.b); + }); + }); + + describe('#merge', function() { + it('merges options from another object', function() { + var option = new Options({a: true, b: false}); + option.merge({b: true}); + assert.strictEqual(true, option.value.a); + assert.strictEqual(true, option.value.b); + }); + it('does nothing when arguments are undefined', function() { + var option = new Options({a: true, b: false}); + option.merge(undefined); + assert.strictEqual(true, option.value.a); + assert.strictEqual(false, option.value.b); + }); + it('cannot set values that werent already there', function() { + var option = new Options({a: true, b: false}); + option.merge({c: true}); + assert.strictEqual('undefined', typeof option.value.c); + }); + it('can require certain options to be defined', function() { + var option = new Options({a: true, b: false, c: 3}); + var caughtException = false; + try { + option.merge({}, ['a', 'b', 'c']); + } + catch (e) { + caughtException = e.toString() == 'Error: options a, b and c must be defined'; + } + assert.strictEqual(true, caughtException); + }); + it('can require certain options to be defined, when options are undefined', function() { + var option = new Options({a: true, b: false, c: 3}); + var caughtException = false; + try { + option.merge(undefined, ['a', 'b', 'c']); + } + catch (e) { + caughtException = e.toString() == 'Error: options a, b and c must be defined'; + } + assert.strictEqual(true, caughtException); + }); + it('returns "this"', function() { + var option = new Options({a: true, b: false, c: 3}); + assert.strictEqual(option, option.merge()); + }); + }); + + describe('#copy', function() { + it('returns a new object with the indicated options', function() { + var option = new Options({a: true, b: false, c: 3}); + option.merge({c: 4}); + var obj = option.copy(['a', 'c']); + assert.strictEqual(true, obj.a); + assert.strictEqual(4, obj.c); + assert.strictEqual('undefined', typeof obj.b); + }); + }); + + describe('#value', function() { + it('can be enumerated', function() { + var option = new Options({a: true, b: false}); + assert.strictEqual(2, Object.keys(option.value).length); + }); + it('can not be used to set values', function() { + var option = new Options({a: true, b: false}); + option.value.b = true; + assert.strictEqual(false, option.value.b); + }); + it('can not be used to add values', function() { + var option = new Options({a: true, b: false}); + option.value.c = 3; + assert.strictEqual('undefined', typeof option.value.c); + }); + }); + + describe('#isDefined', function() { + it('returns true if the named value is defined', function() { + var option = new Options({a: undefined}); + assert.strictEqual(false, option.isDefined('a')); + option.merge({a: false}); + assert.strictEqual(true, option.isDefined('a')); + }); + }); + + describe('#isDefinedAndNonNull', function() { + it('returns true if the named value is defined and non-null', function() { + var option = new Options({a: undefined}); + assert.strictEqual(false, option.isDefinedAndNonNull('a')); + option.merge({a: null}); + assert.strictEqual(false, option.isDefinedAndNonNull('a')); + option.merge({a: 2}); + assert.strictEqual(true, option.isDefinedAndNonNull('a')); + }); + }); + + describe('#read', function() { + it('reads and merges config from a file', function() { + var option = new Options({a: true, b: true}); + option.read(__dirname + '/fixtures/test.conf'); + assert.strictEqual('foobar', option.value.a); + assert.strictEqual(false, option.value.b); + }); + + it('asynchronously reads and merges config from a file when a callback is passed', function(done) { + var option = new Options({a: true, b: true}); + option.read(__dirname + '/fixtures/test.conf', function(error) { + assert.strictEqual('foobar', option.value.a); + assert.strictEqual(false, option.value.b); + done(); + }); + }); + }); + + describe('#reset', function() { + it('resets options to defaults', function() { + var option = new Options({a: true, b: false}); + option.merge({b: true}); + assert.strictEqual(true, option.value.b); + option.reset(); + assert.strictEqual(false, option.value.b); + }); + }); + + it('is immutable', function() { + var option = new Options({a: true, b: false}); + option.foo = 2; + assert.strictEqual('undefined', typeof option.foo); + }); +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/.npmignore b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/.npmignore new file mode 100644 index 00000000..6bfffbb7 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/.npmignore @@ -0,0 +1,5 @@ +npm-debug.log +node_modules +.*.swp +.lock-* +build/ diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/README.md b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/README.md new file mode 100644 index 00000000..55eb3c11 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/README.md @@ -0,0 +1,3 @@ +# tinycolor # + +This is a no-fuzz, barebone, zero muppetry color module for node.js. \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/example.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/example.js new file mode 100644 index 00000000..f7540468 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/example.js @@ -0,0 +1,3 @@ +require('./tinycolor'); +console.log('this should be red and have an underline!'.grey.underline); +console.log('this should have a blue background!'.bgBlue); \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/package.json new file mode 100644 index 00000000..c9a34e93 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/package.json @@ -0,0 +1,28 @@ +{ + "author": { + "name": "Einar Otto Stangvik", + "email": "einaros@gmail.com", + "url": "http://2x.io" + }, + "name": "tinycolor", + "description": "a to-the-point color module for node", + "version": "0.0.1", + "repository": { + "type": "git", + "url": "git://github.com/einaros/tinycolor.git" + }, + "engines": { + "node": ">=0.4.0" + }, + "dependencies": {}, + "devDependencies": {}, + "main": "tinycolor", + "readme": "# tinycolor #\n\nThis is a no-fuzz, barebone, zero muppetry color module for node.js.", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/einaros/tinycolor/issues" + }, + "homepage": "https://github.com/einaros/tinycolor", + "_id": "tinycolor@0.0.1", + "_from": "tinycolor@0.x" +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/tinycolor.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/tinycolor.js new file mode 100644 index 00000000..36e552c4 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/tinycolor.js @@ -0,0 +1,31 @@ +var styles = { + 'bold': ['\033[1m', '\033[22m'], + 'italic': ['\033[3m', '\033[23m'], + 'underline': ['\033[4m', '\033[24m'], + 'inverse': ['\033[7m', '\033[27m'], + 'black': ['\033[30m', '\033[39m'], + 'red': ['\033[31m', '\033[39m'], + 'green': ['\033[32m', '\033[39m'], + 'yellow': ['\033[33m', '\033[39m'], + 'blue': ['\033[34m', '\033[39m'], + 'magenta': ['\033[35m', '\033[39m'], + 'cyan': ['\033[36m', '\033[39m'], + 'white': ['\033[37m', '\033[39m'], + 'default': ['\033[39m', '\033[39m'], + 'grey': ['\033[90m', '\033[39m'], + 'bgBlack': ['\033[40m', '\033[49m'], + 'bgRed': ['\033[41m', '\033[49m'], + 'bgGreen': ['\033[42m', '\033[49m'], + 'bgYellow': ['\033[43m', '\033[49m'], + 'bgBlue': ['\033[44m', '\033[49m'], + 'bgMagenta': ['\033[45m', '\033[49m'], + 'bgCyan': ['\033[46m', '\033[49m'], + 'bgWhite': ['\033[47m', '\033[49m'], + 'bgDefault': ['\033[49m', '\033[49m'] +} +Object.keys(styles).forEach(function(style) { + Object.defineProperty(String.prototype, style, { + get: function() { return styles[style][0] + this + styles[style][1]; }, + enumerable: false + }); +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/package.json new file mode 100644 index 00000000..71f2d880 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/package.json @@ -0,0 +1,61 @@ +{ + "author": { + "name": "Einar Otto Stangvik", + "email": "einaros@gmail.com", + "url": "http://2x.io" + }, + "name": "ws", + "description": "simple to use, blazing fast and thoroughly tested websocket client, server and console for node.js, up-to-date against RFC-6455", + "version": "0.4.31", + "keywords": [ + "Hixie", + "HyBi", + "Push", + "RFC-6455", + "WebSocket", + "WebSockets", + "real-time" + ], + "repository": { + "type": "git", + "url": "git://github.com/einaros/ws.git" + }, + "bin": { + "wscat": "./bin/wscat" + }, + "scripts": { + "test": "make test", + "install": "(node-gyp rebuild 2> builderror.log) || (exit 0)" + }, + "engines": { + "node": ">=0.4.0" + }, + "dependencies": { + "commander": "~0.6.1", + "nan": "~0.3.0", + "tinycolor": "0.x", + "options": ">=0.0.5" + }, + "devDependencies": { + "mocha": "1.12.0", + "should": "1.2.x", + "expect.js": "0.2.x", + "benchmark": "0.3.x", + "ansi": "latest" + }, + "browser": "./lib/browser.js", + "component": { + "scripts": { + "ws/index.js": "./lib/browser.js" + } + }, + "gypfile": true, + "readme": "[![Build Status](https://secure.travis-ci.org/einaros/ws.png)](http://travis-ci.org/einaros/ws)\n\n# ws: a node.js websocket library #\n\n`ws` is a simple to use websocket implementation, up-to-date against RFC-6455, and [probably the fastest WebSocket library for node.js](http://web.archive.org/web/20130314230536/http://hobbycoding.posterous.com/the-fastest-websocket-module-for-nodejs).\n\nPasses the quite extensive Autobahn test suite. See http://einaros.github.com/ws for the full reports.\n\nComes with a command line utility, `wscat`, which can either act as a server (--listen), or client (--connect); Use it to debug simple websocket services.\n\n## Protocol support ##\n\n* **Hixie draft 76** (Old and deprecated, but still in use by Safari and Opera. Added to ws version 0.4.2, but server only. Can be disabled by setting the `disableHixie` option to true.)\n* **HyBi drafts 07-12** (Use the option `protocolVersion: 8`, or argument `-p 8` for wscat)\n* **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`, or argument `-p 13` for wscat)\n\n_See the echo.websocket.org example below for how to use the `protocolVersion` option._\n\n## Usage ##\n\n### Installing ###\n\n`npm install ws`\n\n### Sending and receiving text data ###\n\n```js\nvar WebSocket = require('ws');\nvar ws = new WebSocket('ws://www.host.com/path');\nws.on('open', function() {\n ws.send('something');\n});\nws.on('message', function(data, flags) {\n // flags.binary will be set if a binary data is received\n // flags.masked will be set if the data was masked\n});\n```\n\n### Sending binary data ###\n\n```js\nvar WebSocket = require('ws');\nvar ws = new WebSocket('ws://www.host.com/path');\nws.on('open', function() {\n var array = new Float32Array(5);\n for (var i = 0; i < array.length; ++i) array[i] = i / 2;\n ws.send(array, {binary: true, mask: true});\n});\n```\n\nSetting `mask`, as done for the send options above, will cause the data to be masked according to the websocket protocol. The same option applies for text data.\n\n### Server example ###\n\n```js\nvar WebSocketServer = require('ws').Server\n , wss = new WebSocketServer({port: 8080});\nwss.on('connection', function(ws) {\n ws.on('message', function(message) {\n console.log('received: %s', message);\n });\n ws.send('something');\n});\n```\n\n### Server sending broadcast data ###\n\n```js\nvar WebSocketServer = require('ws').Server\n , wss = new WebSocketServer({port: 8080});\n \nwss.broadcast = function(data) {\n\tfor(var i in this.clients)\n\t\tthis.clients[i].send(data);\n};\n```\n\n### Error handling best practices ###\n\n```js\n// If the WebSocket is closed before the following send is attempted\nws.send('something');\n\n// Errors (both immediate and async write errors) can be detected in an optional callback.\n// The callback is also the only way of being notified that data has actually been sent.\nws.send('something', function(error) {\n // if error is null, the send has been completed,\n // otherwise the error object will indicate what failed.\n});\n\n// Immediate errors can also be handled with try/catch-blocks, but **note**\n// that since sends are inherently asynchronous, socket write failures will *not*\n// be captured when this technique is used.\ntry {\n ws.send('something');\n}\ncatch (e) {\n // handle error\n}\n```\n\n### echo.websocket.org demo ###\n\n```js\nvar WebSocket = require('ws');\nvar ws = new WebSocket('ws://echo.websocket.org/', {protocolVersion: 8, origin: 'http://websocket.org'});\nws.on('open', function() {\n console.log('connected');\n ws.send(Date.now().toString(), {mask: true});\n});\nws.on('close', function() {\n console.log('disconnected');\n});\nws.on('message', function(data, flags) {\n console.log('Roundtrip time: ' + (Date.now() - parseInt(data)) + 'ms', flags);\n setTimeout(function() {\n ws.send(Date.now().toString(), {mask: true});\n }, 500);\n});\n```\n\n### wscat against echo.websocket.org ###\n\n $ npm install -g ws\n $ wscat -c ws://echo.websocket.org -p 8\n connected (press CTRL+C to quit)\n > hi there\n < hi there\n > are you a happy parrot?\n < are you a happy parrot?\n\n### Other examples ###\n\nFor a full example with a browser client communicating with a ws server, see the examples folder.\n\nNote that the usage together with Express 3.0 is quite different from Express 2.x. The difference is expressed in the two different serverstats-examples.\n\nOtherwise, see the test cases.\n\n### Running the tests ###\n\n`make test`\n\n## API Docs ##\n\nSee the doc/ directory for Node.js-like docs for the ws classes.\n\n## License ##\n\n(The MIT License)\n\nCopyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/einaros/ws/issues" + }, + "homepage": "https://github.com/einaros/ws", + "_id": "ws@0.4.31", + "_from": "ws@0.4.x" +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/src/bufferutil.cc b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/src/bufferutil.cc new file mode 100644 index 00000000..f06777f4 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/src/bufferutil.cc @@ -0,0 +1,117 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "nan.h" + +using namespace v8; +using namespace node; + +class BufferUtil : public ObjectWrap +{ +public: + + static void Initialize(v8::Handle target) + { + NanScope(); + Local t = FunctionTemplate::New(New); + t->InstanceTemplate()->SetInternalFieldCount(1); + NODE_SET_METHOD(t, "unmask", BufferUtil::Unmask); + NODE_SET_METHOD(t, "mask", BufferUtil::Mask); + NODE_SET_METHOD(t, "merge", BufferUtil::Merge); + target->Set(String::NewSymbol("BufferUtil"), t->GetFunction()); + } + +protected: + + static NAN_METHOD(New) + { + NanScope(); + BufferUtil* bufferUtil = new BufferUtil(); + bufferUtil->Wrap(args.This()); + NanReturnValue(args.This()); + } + + static NAN_METHOD(Merge) + { + NanScope(); + Local bufferObj = args[0]->ToObject(); + char* buffer = Buffer::Data(bufferObj); + Local array = Local::Cast(args[1]); + unsigned int arrayLength = array->Length(); + size_t offset = 0; + unsigned int i; + for (i = 0; i < arrayLength; ++i) { + Local src = array->Get(i)->ToObject(); + size_t length = Buffer::Length(src); + memcpy(buffer + offset, Buffer::Data(src), length); + offset += length; + } + NanReturnValue(True()); + } + + static NAN_METHOD(Unmask) + { + NanScope(); + Local buffer_obj = args[0]->ToObject(); + size_t length = Buffer::Length(buffer_obj); + Local mask_obj = args[1]->ToObject(); + unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj); + unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj); + size_t len32 = length / 4; + unsigned int i; + for (i = 0; i < len32; ++i) *(from + i) ^= *mask; + from += i; + switch (length % 4) { + case 3: *((unsigned char*)from+2) = *((unsigned char*)from+2) ^ ((unsigned char*)mask)[2]; + case 2: *((unsigned char*)from+1) = *((unsigned char*)from+1) ^ ((unsigned char*)mask)[1]; + case 1: *((unsigned char*)from ) = *((unsigned char*)from ) ^ ((unsigned char*)mask)[0]; + case 0:; + } + NanReturnValue(True()); + } + + static NAN_METHOD(Mask) + { + NanScope(); + Local buffer_obj = args[0]->ToObject(); + Local mask_obj = args[1]->ToObject(); + unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj); + Local output_obj = args[2]->ToObject(); + unsigned int dataOffset = args[3]->Int32Value(); + unsigned int length = args[4]->Int32Value(); + unsigned int* to = (unsigned int*)(Buffer::Data(output_obj) + dataOffset); + unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj); + unsigned int len32 = length / 4; + unsigned int i; + for (i = 0; i < len32; ++i) *(to + i) = *(from + i) ^ *mask; + to += i; + from += i; + switch (length % 4) { + case 3: *((unsigned char*)to+2) = *((unsigned char*)from+2) ^ *((unsigned char*)mask+2); + case 2: *((unsigned char*)to+1) = *((unsigned char*)from+1) ^ *((unsigned char*)mask+1); + case 1: *((unsigned char*)to ) = *((unsigned char*)from ) ^ *((unsigned char*)mask); + case 0:; + } + NanReturnValue(True()); + } +}; + +extern "C" void init (Handle target) +{ + NanScope(); + BufferUtil::Initialize(target); +} + +NODE_MODULE(bufferutil, init) + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/src/validation.cc b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/src/validation.cc new file mode 100644 index 00000000..528eda1f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/src/validation.cc @@ -0,0 +1,145 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +#include +#include +#include +#include +#include +#include +#include +#include "nan.h" + +using namespace v8; +using namespace node; + +#define UNI_SUR_HIGH_START (uint32_t) 0xD800 +#define UNI_SUR_LOW_END (uint32_t) 0xDFFF +#define UNI_REPLACEMENT_CHAR (uint32_t) 0x0000FFFD +#define UNI_MAX_LEGAL_UTF32 (uint32_t) 0x0010FFFF + +static const uint8_t trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +static const uint32_t offsetsFromUTF8[6] = { + 0x00000000, 0x00003080, 0x000E2080, + 0x03C82080, 0xFA082080, 0x82082080 +}; + +static int isLegalUTF8(const uint8_t *source, const int length) +{ + uint8_t a; + const uint8_t *srcptr = source+length; + switch (length) { + default: return 0; + /* Everything else falls through when "true"... */ + /* RFC3629 makes 5 & 6 bytes UTF-8 illegal + case 6: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; + case 5: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; + case 2: if ((a = (*--srcptr)) > 0xBF) return 0; + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return 0; break; + case 0xED: if (a > 0x9F) return 0; break; + case 0xF0: if (a < 0x90) return 0; break; + case 0xF4: if (a > 0x8F) return 0; break; + default: if (a < 0x80) return 0; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return 0; + } + if (*source > 0xF4) return 0; + return 1; +} + +int is_valid_utf8 (size_t len, char *value) +{ + /* is the string valid UTF-8? */ + for (unsigned int i = 0; i < len; i++) { + uint32_t ch = 0; + uint8_t extrabytes = trailingBytesForUTF8[(uint8_t) value[i]]; + + if (extrabytes + i >= len) + return 0; + + if (isLegalUTF8 ((uint8_t *) (value + i), extrabytes + 1) == 0) return 0; + + switch (extrabytes) { + case 5 : ch += (uint8_t) value[i++]; ch <<= 6; + case 4 : ch += (uint8_t) value[i++]; ch <<= 6; + case 3 : ch += (uint8_t) value[i++]; ch <<= 6; + case 2 : ch += (uint8_t) value[i++]; ch <<= 6; + case 1 : ch += (uint8_t) value[i++]; ch <<= 6; + case 0 : ch += (uint8_t) value[i]; + } + + ch -= offsetsFromUTF8[extrabytes]; + + if (ch <= UNI_MAX_LEGAL_UTF32) { + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) + return 0; + } else { + return 0; + } + } + + return 1; +} + +class Validation : public ObjectWrap +{ +public: + + static void Initialize(v8::Handle target) + { + HandleScope scope; + Local t = FunctionTemplate::New(New); + t->InstanceTemplate()->SetInternalFieldCount(1); + NODE_SET_METHOD(t, "isValidUTF8", Validation::IsValidUTF8); + target->Set(String::NewSymbol("Validation"), t->GetFunction()); + } + +protected: + + static NAN_METHOD(New) + { + NanScope(); + Validation* validation = new Validation(); + validation->Wrap(args.This()); + NanReturnValue(args.This()); + } + + static NAN_METHOD(IsValidUTF8) + { + NanScope(); + if (!Buffer::HasInstance(args[0])) { + return NanThrowTypeError("First argument needs to be a buffer"); + } + Local buffer_obj = args[0]->ToObject(); + char *buffer_data = Buffer::Data(buffer_obj); + size_t buffer_length = Buffer::Length(buffer_obj); + NanReturnValue(is_valid_utf8(buffer_length, buffer_data) == 1 ? True() : False()); + } +}; + +extern "C" void init (Handle target) +{ + NanScope(); + Validation::Initialize(target); +} + +NODE_MODULE(validation, init) + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/BufferPool.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/BufferPool.test.js new file mode 100644 index 00000000..1ee7ff0f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/BufferPool.test.js @@ -0,0 +1,63 @@ +var BufferPool = require('../lib/BufferPool'); +require('should'); + +describe('BufferPool', function() { + describe('#ctor', function() { + it('allocates pool', function() { + var db = new BufferPool(1000); + db.size.should.eql(1000); + }); + }); + describe('#get', function() { + it('grows the pool if necessary', function() { + var db = new BufferPool(1000); + var buf = db.get(2000); + db.size.should.be.above(1000); + db.used.should.eql(2000); + buf.length.should.eql(2000); + }); + it('grows the pool after the first call, if necessary', function() { + var db = new BufferPool(1000); + var buf = db.get(1000); + db.used.should.eql(1000); + db.size.should.eql(1000); + buf.length.should.eql(1000); + var buf2 = db.get(1000); + db.used.should.eql(2000); + db.size.should.be.above(1000); + buf2.length.should.eql(1000); + }); + it('grows the pool according to the growStrategy if necessary', function() { + var db = new BufferPool(1000, function(db, length) { + return db.size + 2345; + }); + var buf = db.get(2000); + db.size.should.eql(3345); + buf.length.should.eql(2000); + }); + it('doesnt grow the pool if theres enough room available', function() { + var db = new BufferPool(1000); + var buf = db.get(1000); + db.size.should.eql(1000); + buf.length.should.eql(1000); + }); + }); + describe('#reset', function() { + it('shinks the pool', function() { + var db = new BufferPool(1000); + var buf = db.get(2000); + db.reset(true); + db.size.should.eql(1000); + }); + it('shrinks the pool according to the shrinkStrategy', function() { + var db = new BufferPool(1000, function(db, length) { + return db.used + length; + }, function(db) { + return 0; + }); + var buf = db.get(2000); + db.reset(true); + db.size.should.eql(0); + }); + }); +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Receiver.hixie.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Receiver.hixie.test.js new file mode 100644 index 00000000..043d3bc4 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Receiver.hixie.test.js @@ -0,0 +1,158 @@ +var assert = require('assert') + , expect = require('expect.js') + , Receiver = require('../lib/Receiver.hixie'); +require('./hybi-common'); + +describe('Receiver', function() { + it('can parse text message', function() { + var p = new Receiver(); + var packet = '00 48 65 6c 6c 6f ff'; + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal('Hello', data); + }; + + p.add(getBufferFromHexString(packet)); + expect(gotData).to.equal(true); + }); + + it('can parse multiple text messages', function() { + var p = new Receiver(); + var packet = '00 48 65 6c 6c 6f ff 00 48 65 6c 6c 6f ff'; + + var gotData = false; + var messages = []; + p.ontext = function(data) { + gotData = true; + messages.push(data); + }; + + p.add(getBufferFromHexString(packet)); + expect(gotData).to.equal(true); + for (var i = 0; i < 2; ++i) { + expect(messages[i]).to.equal('Hello'); + } + }); + + it('can parse empty message', function() { + var p = new Receiver(); + var packet = '00 ff'; + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal('', data); + }; + + p.add(getBufferFromHexString(packet)); + expect(gotData).to.equal(true); + }); + + it('can parse text messages delivered over multiple frames', function() { + var p = new Receiver(); + var packets = [ + '00 48', + '65 6c 6c', + '6f ff 00 48', + '65', + '6c 6c 6f', + 'ff' + ]; + + var gotData = false; + var messages = []; + p.ontext = function(data) { + gotData = true; + messages.push(data); + }; + + for (var i = 0; i < packets.length; ++i) { + p.add(getBufferFromHexString(packets[i])); + } + expect(gotData).to.equal(true); + for (var i = 0; i < 2; ++i) { + expect(messages[i]).to.equal('Hello'); + } + }); + + it('emits an error if a payload doesnt start with 0x00', function() { + var p = new Receiver(); + var packets = [ + '00 6c ff', + '00 6c ff ff', + 'ff 00 6c ff 00 6c ff', + '00', + '6c 6c 6f', + 'ff' + ]; + + var gotData = false; + var gotError = false; + var messages = []; + p.ontext = function(data) { + gotData = true; + messages.push(data); + }; + p.onerror = function(reason, code) { + gotError = code == true; + }; + + for (var i = 0; i < packets.length && !gotError; ++i) { + p.add(getBufferFromHexString(packets[i])); + } + expect(gotError).to.equal(true); + expect(messages[0]).to.equal('l'); + expect(messages[1]).to.equal('l'); + expect(messages.length).to.equal(2); + }); + + it('can parse close messages', function() { + var p = new Receiver(); + var packets = [ + 'ff 00' + ]; + + var gotClose = false; + var gotError = false; + p.onclose = function() { + gotClose = true; + }; + p.onerror = function(reason, code) { + gotError = code == true; + }; + + for (var i = 0; i < packets.length && !gotError; ++i) { + p.add(getBufferFromHexString(packets[i])); + } + expect(gotClose).to.equal(true); + expect(gotError).to.equal(false); + }); + + it('can parse binary messages delivered over multiple frames', function() { + var p = new Receiver(); + var packets = [ + '80 05 48', + '65 6c 6c', + '6f 80 80 05 48', + '65', + '6c 6c 6f' + ]; + + var gotData = false; + var messages = []; + p.ontext = function(data) { + gotData = true; + messages.push(data); + }; + + for (var i = 0; i < packets.length; ++i) { + p.add(getBufferFromHexString(packets[i])); + } + expect(gotData).to.equal(true); + for (var i = 0; i < 2; ++i) { + expect(messages[i]).to.equal('Hello'); + } + }); +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Receiver.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Receiver.test.js new file mode 100644 index 00000000..b0b5c0a4 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Receiver.test.js @@ -0,0 +1,255 @@ +var assert = require('assert') + , Receiver = require('../lib/Receiver'); +require('should'); +require('./hybi-common'); + +describe('Receiver', function() { + it('can parse unmasked text message', function() { + var p = new Receiver(); + var packet = '81 05 48 65 6c 6c 6f'; + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal('Hello', data); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse close message', function() { + var p = new Receiver(); + var packet = '88 00'; + + var gotClose = false; + p.onclose = function(data) { + gotClose = true; + }; + + p.add(getBufferFromHexString(packet)); + gotClose.should.be.ok; + }); + it('can parse masked text message', function() { + var p = new Receiver(); + var packet = '81 93 34 83 a8 68 01 b9 92 52 4f a1 c6 09 59 e6 8a 52 16 e6 cb 00 5b a1 d5'; + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal('5:::{"name":"echo"}', data); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a masked text message longer than 125 bytes', function() { + var p = new Receiver(); + var message = 'A'; + for (var i = 0; i < 300; ++i) message += (i % 5).toString(); + var packet = '81 FE ' + pack(4, message.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal(message, data); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a really long masked text message', function() { + var p = new Receiver(); + var message = 'A'; + for (var i = 0; i < 64*1024; ++i) message += (i % 5).toString(); + var packet = '81 FF ' + pack(16, message.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal(message, data); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a fragmented masked text message of 300 bytes', function() { + var p = new Receiver(); + var message = 'A'; + for (var i = 0; i < 300; ++i) message += (i % 5).toString(); + var msgpiece1 = message.substr(0, 150); + var msgpiece2 = message.substr(150); + var packet1 = '01 FE ' + pack(4, msgpiece1.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece1, '34 83 a8 68')); + var packet2 = '80 FE ' + pack(4, msgpiece2.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece2, '34 83 a8 68')); + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal(message, data); + }; + + p.add(getBufferFromHexString(packet1)); + p.add(getBufferFromHexString(packet2)); + gotData.should.be.ok; + }); + it('can parse a ping message', function() { + var p = new Receiver(); + var message = 'Hello'; + var packet = '89 ' + getHybiLengthAsHexString(message.length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotPing = false; + p.onping = function(data) { + gotPing = true; + assert.equal(message, data); + }; + + p.add(getBufferFromHexString(packet)); + gotPing.should.be.ok; + }); + it('can parse a ping with no data', function() { + var p = new Receiver(); + var packet = '89 00'; + + var gotPing = false; + p.onping = function(data) { + gotPing = true; + }; + + p.add(getBufferFromHexString(packet)); + gotPing.should.be.ok; + }); + it('can parse a fragmented masked text message of 300 bytes with a ping in the middle', function() { + var p = new Receiver(); + var message = 'A'; + for (var i = 0; i < 300; ++i) message += (i % 5).toString(); + + var msgpiece1 = message.substr(0, 150); + var packet1 = '01 FE ' + pack(4, msgpiece1.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece1, '34 83 a8 68')); + + var pingMessage = 'Hello'; + var pingPacket = '89 ' + getHybiLengthAsHexString(pingMessage.length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(pingMessage, '34 83 a8 68')); + + var msgpiece2 = message.substr(150); + var packet2 = '80 FE ' + pack(4, msgpiece2.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece2, '34 83 a8 68')); + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal(message, data); + }; + var gotPing = false; + p.onping = function(data) { + gotPing = true; + assert.equal(pingMessage, data); + }; + + p.add(getBufferFromHexString(packet1)); + p.add(getBufferFromHexString(pingPacket)); + p.add(getBufferFromHexString(packet2)); + gotData.should.be.ok; + gotPing.should.be.ok; + }); + it('can parse a fragmented masked text message of 300 bytes with a ping in the middle, which is delievered over sevaral tcp packets', function() { + var p = new Receiver(); + var message = 'A'; + for (var i = 0; i < 300; ++i) message += (i % 5).toString(); + + var msgpiece1 = message.substr(0, 150); + var packet1 = '01 FE ' + pack(4, msgpiece1.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece1, '34 83 a8 68')); + + var pingMessage = 'Hello'; + var pingPacket = '89 ' + getHybiLengthAsHexString(pingMessage.length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(pingMessage, '34 83 a8 68')); + + var msgpiece2 = message.substr(150); + var packet2 = '80 FE ' + pack(4, msgpiece2.length) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(msgpiece2, '34 83 a8 68')); + + var gotData = false; + p.ontext = function(data) { + gotData = true; + assert.equal(message, data); + }; + var gotPing = false; + p.onping = function(data) { + gotPing = true; + assert.equal(pingMessage, data); + }; + + var buffers = []; + buffers = buffers.concat(splitBuffer(getBufferFromHexString(packet1))); + buffers = buffers.concat(splitBuffer(getBufferFromHexString(pingPacket))); + buffers = buffers.concat(splitBuffer(getBufferFromHexString(packet2))); + for (var i = 0; i < buffers.length; ++i) { + p.add(buffers[i]); + } + gotData.should.be.ok; + gotPing.should.be.ok; + }); + it('can parse a 100 byte long masked binary message', function() { + var p = new Receiver(); + var length = 100; + var message = new Buffer(length); + for (var i = 0; i < length; ++i) message[i] = i % 256; + var originalMessage = getHexStringFromBuffer(message); + var packet = '82 ' + getHybiLengthAsHexString(length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotData = false; + p.onbinary = function(data) { + gotData = true; + assert.equal(originalMessage, getHexStringFromBuffer(data)); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a 256 byte long masked binary message', function() { + var p = new Receiver(); + var length = 256; + var message = new Buffer(length); + for (var i = 0; i < length; ++i) message[i] = i % 256; + var originalMessage = getHexStringFromBuffer(message); + var packet = '82 ' + getHybiLengthAsHexString(length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotData = false; + p.onbinary = function(data) { + gotData = true; + assert.equal(originalMessage, getHexStringFromBuffer(data)); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a 200kb long masked binary message', function() { + var p = new Receiver(); + var length = 200 * 1024; + var message = new Buffer(length); + for (var i = 0; i < length; ++i) message[i] = i % 256; + var originalMessage = getHexStringFromBuffer(message); + var packet = '82 ' + getHybiLengthAsHexString(length, true) + ' 34 83 a8 68 ' + getHexStringFromBuffer(mask(message, '34 83 a8 68')); + + var gotData = false; + p.onbinary = function(data) { + gotData = true; + assert.equal(originalMessage, getHexStringFromBuffer(data)); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); + it('can parse a 200kb long unmasked binary message', function() { + var p = new Receiver(); + var length = 200 * 1024; + var message = new Buffer(length); + for (var i = 0; i < length; ++i) message[i] = i % 256; + var originalMessage = getHexStringFromBuffer(message); + var packet = '82 ' + getHybiLengthAsHexString(length, false) + ' ' + getHexStringFromBuffer(message); + + var gotData = false; + p.onbinary = function(data) { + gotData = true; + assert.equal(originalMessage, getHexStringFromBuffer(data)); + }; + + p.add(getBufferFromHexString(packet)); + gotData.should.be.ok; + }); +}); + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Sender.hixie.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Sender.hixie.test.js new file mode 100644 index 00000000..783f8922 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Sender.hixie.test.js @@ -0,0 +1,134 @@ +var assert = require('assert') + , Sender = require('../lib/Sender.hixie'); +require('should'); +require('./hybi-common'); + +describe('Sender', function() { + describe('#send', function() { + it('frames and sends a text message', function(done) { + var message = 'Hello world'; + var received; + var socket = { + write: function(data, encoding, cb) { + received = data; + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.send(message, {}, function() { + received.toString('utf8').should.eql('\u0000' + message + '\ufffd'); + done(); + }); + }); + + it('frames and sends an empty message', function(done) { + var socket = { + write: function(data, encoding, cb) { + done(); + } + }; + var sender = new Sender(socket, {}); + sender.send('', {}, function() {}); + }); + + it('frames and sends a buffer', function(done) { + var received; + var socket = { + write: function(data, encoding, cb) { + received = data; + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.send(new Buffer('foobar'), {}, function() { + received.toString('utf8').should.eql('\u0000foobar\ufffd'); + done(); + }); + }); + + it('frames and sends a binary message', function(done) { + var message = 'Hello world'; + var received; + var socket = { + write: function(data, encoding, cb) { + received = data; + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.send(message, {binary: true}, function() { + received.toString('hex').should.eql( + // 0x80 0x0b H e l l o w o r l d + '800b48656c6c6f20776f726c64'); + done(); + }); + }); +/* + it('throws an exception for binary data', function(done) { + var socket = { + write: function(data, encoding, cb) { + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.on('error', function() { + done(); + }); + sender.send(new Buffer(100), {binary: true}, function() {}); + }); +*/ + it('can fauxe stream data', function(done) { + var received = []; + var socket = { + write: function(data, encoding, cb) { + received.push(data); + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.send(new Buffer('foobar'), { fin: false }, function() {}); + sender.send('bazbar', { fin: false }, function() {}); + sender.send(new Buffer('end'), { fin: true }, function() { + received[0].toString('utf8').should.eql('\u0000foobar'); + received[1].toString('utf8').should.eql('bazbar'); + received[2].toString('utf8').should.eql('end\ufffd'); + done(); + }); + }); + }); + + describe('#close', function() { + it('sends a hixie close frame', function(done) { + var received; + var socket = { + write: function(data, encoding, cb) { + received = data; + process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.close(null, null, null, function() { + received.toString('utf8').should.eql('\ufffd\u0000'); + done(); + }); + }); + + it('sends a message end marker if fauxe streaming has started, before hixie close frame', function(done) { + var received = []; + var socket = { + write: function(data, encoding, cb) { + received.push(data); + if (cb) process.nextTick(cb); + } + }; + var sender = new Sender(socket, {}); + sender.send(new Buffer('foobar'), { fin: false }, function() {}); + sender.close(null, null, null, function() { + received[0].toString('utf8').should.eql('\u0000foobar'); + received[1].toString('utf8').should.eql('\ufffd'); + received[2].toString('utf8').should.eql('\ufffd\u0000'); + done(); + }); + }); + }); +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Sender.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Sender.test.js new file mode 100644 index 00000000..43b4864d --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Sender.test.js @@ -0,0 +1,24 @@ +var Sender = require('../lib/Sender'); +require('should'); + +describe('Sender', function() { + describe('#frameAndSend', function() { + it('does not modify a masked binary buffer', function() { + var sender = new Sender({ write: function() {} }); + var buf = new Buffer([1, 2, 3, 4, 5]); + sender.frameAndSend(2, buf, true, true); + buf[0].should.eql(1); + buf[1].should.eql(2); + buf[2].should.eql(3); + buf[3].should.eql(4); + buf[4].should.eql(5); + }); + + it('does not modify a masked text buffer', function() { + var sender = new Sender({ write: function() {} }); + var text = 'hi there'; + sender.frameAndSend(1, text, true, true); + text.should.eql('hi there'); + }); + }); +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Validation.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Validation.test.js new file mode 100644 index 00000000..37c33993 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Validation.test.js @@ -0,0 +1,23 @@ +var Validation = require('../lib/Validation').Validation; +require('should'); + +describe('Validation', function() { + describe('isValidUTF8', function() { + it('should return true for a valid utf8 string', function() { + var validBuffer = new Buffer('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque gravida mattis rhoncus. Donec iaculis, metus quis varius accumsan, erat mauris condimentum diam, et egestas erat enim ut ligula. Praesent sollicitudin tellus eget dolor euismod euismod. Nullam ac augue nec neque varius luctus. Curabitur elit mi, consequat ultricies adipiscing mollis, scelerisque in erat. Phasellus facilisis fermentum ullamcorper. Nulla et sem eu arcu pharetra pellentesque. Praesent consectetur tempor justo, vel iaculis dui ullamcorper sit amet. Integer tristique viverra ullamcorper. Vivamus laoreet, nulla eget suscipit eleifend, lacus lectus feugiat libero, non fermentum erat nisi at risus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut pulvinar dignissim tellus, eu dignissim lorem vulputate quis. Morbi ut pulvinar augue.'); + Validation.isValidUTF8(validBuffer).should.be.ok; + }); + it('should return false for an erroneous string', function() { + var invalidBuffer = new Buffer([0xce, 0xba, 0xe1, 0xbd, 0xb9, 0xcf, 0x83, 0xce, 0xbc, 0xce, 0xb5, 0xed, 0xa0, 0x80, 0x65, 0x64, 0x69, 0x74, 0x65, 0x64]); + Validation.isValidUTF8(invalidBuffer).should.not.be.ok; + }); + it('should return true for valid cases from the autobahn test suite', function() { + Validation.isValidUTF8(new Buffer('\xf0\x90\x80\x80')).should.be.ok; + Validation.isValidUTF8(new Buffer([0xf0, 0x90, 0x80, 0x80])).should.be.ok; + }); + it('should return false for erroneous autobahn strings', function() { + Validation.isValidUTF8(new Buffer([0xce, 0xba, 0xe1, 0xbd])).should.not.be.ok; + }); + }); +}); + diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocket.integration.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocket.integration.js new file mode 100644 index 00000000..5d4f426f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocket.integration.js @@ -0,0 +1,44 @@ +var assert = require('assert') + , WebSocket = require('../') + , server = require('./testserver'); + +var port = 20000; + +function getArrayBuffer(buf) { + var l = buf.length; + var arrayBuf = new ArrayBuffer(l); + var uint8View = new Uint8Array(arrayBuf); + + for (var i = 0; i < l; i++) { + uint8View[i] = buf[i]; + } + return uint8View.buffer; +} + +function areArraysEqual(x, y) { + if (x.length != y.length) return false; + for (var i = 0, l = x.length; i < l; ++i) { + if (x[i] !== y[i]) return false; + } + return true; +} + +describe('WebSocket', function() { + it('communicates successfully with echo service', function(done) { + var ws = new WebSocket('ws://echo.websocket.org/', {protocolVersion: 13, origin: 'http://websocket.org'}); + var str = Date.now().toString(); + var dataReceived = false; + ws.on('open', function() { + ws.send(str, {mask: true}); + }); + ws.on('close', function() { + assert.equal(true, dataReceived); + done(); + }); + ws.on('message', function(data, flags) { + assert.equal(str, data); + ws.terminate(); + dataReceived = true; + }); + }); +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocket.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocket.test.js new file mode 100644 index 00000000..91336b93 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocket.test.js @@ -0,0 +1,1724 @@ +var assert = require('assert') + , https = require('https') + , http = require('http') + , should = require('should') + , WebSocket = require('../') + , WebSocketServer = require('../').Server + , fs = require('fs') + , server = require('./testserver') + , crypto = require('crypto'); + +var port = 20000; + +function getArrayBuffer(buf) { + var l = buf.length; + var arrayBuf = new ArrayBuffer(l); + var uint8View = new Uint8Array(arrayBuf); + for (var i = 0; i < l; i++) { + uint8View[i] = buf[i]; + } + return uint8View.buffer; +} + + +function areArraysEqual(x, y) { + if (x.length != y.length) return false; + for (var i = 0, l = x.length; i < l; ++i) { + if (x[i] !== y[i]) return false; + } + return true; +} + +describe('WebSocket', function() { + describe('#ctor', function() { + it('throws exception for invalid url', function(done) { + try { + var ws = new WebSocket('echo.websocket.org'); + } + catch (e) { + done(); + } + }); + }); + + describe('options', function() { + it('should accept an `agent` option', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var agent = { + addRequest: function() { + wss.close(); + done(); + } + }; + var ws = new WebSocket('ws://localhost:' + port, { agent: agent }); + }); + }); + // GH-227 + it('should accept the `options` object as the 3rd argument', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var agent = { + addRequest: function() { + wss.close(); + done(); + } + }; + var ws = new WebSocket('ws://localhost:' + port, [], { agent: agent }); + }); + }); + }); + + describe('properties', function() { + it('#bytesReceived exposes number of bytes received', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('message', function() { + ws.bytesReceived.should.eql(8); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + ws.send('foobar'); + }); + }); + + it('#url exposes the server url', function(done) { + server.createServer(++port, function(srv) { + var url = 'ws://localhost:' + port; + var ws = new WebSocket(url); + assert.equal(url, ws.url); + ws.terminate(); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('#protocolVersion exposes the protocol version', function(done) { + server.createServer(++port, function(srv) { + var url = 'ws://localhost:' + port; + var ws = new WebSocket(url); + assert.equal(13, ws.protocolVersion); + ws.terminate(); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + describe('#bufferedAmount', function() { + it('defaults to zero', function(done) { + server.createServer(++port, function(srv) { + var url = 'ws://localhost:' + port; + var ws = new WebSocket(url); + assert.equal(0, ws.bufferedAmount); + ws.terminate(); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('defaults to zero upon "open"', function(done) { + server.createServer(++port, function(srv) { + var url = 'ws://localhost:' + port; + var ws = new WebSocket(url); + ws.onopen = function() { + assert.equal(0, ws.bufferedAmount); + ws.terminate(); + ws.on('close', function() { + srv.close(); + done(); + }); + }; + }); + }); + + it('stress kernel write buffer', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(ws) { + while (true) { + if (ws.bufferedAmount > 0) break; + ws.send((new Array(10000)).join('hello')); + } + ws.terminate(); + ws.on('close', function() { + wss.close(); + done(); + }); + }); + }); + }); + + describe('Custom headers', function() { + it('request has an authorization header', function (done) { + var auth = 'test:testpass'; + var srv = http.createServer(function (req, res) {}); + var wss = new WebSocketServer({server: srv}); + srv.listen(++port); + var ws = new WebSocket('ws://' + auth + '@localhost:' + port); + srv.on('upgrade', function (req, socket, head) { + assert(req.headers.authorization, 'auth header exists'); + assert.equal(req.headers.authorization, 'Basic ' + new Buffer(auth).toString('base64')); + ws.terminate(); + ws.on('close', function () { + srv.close(); + wss.close(); + done(); + }); + }); + }); + + it('accepts custom headers', function (done) { + var srv = http.createServer(function (req, res) {}); + var wss = new WebSocketServer({server: srv}); + srv.listen(++port); + + var ws = new WebSocket('ws://localhost:' + port, { + headers: { + 'Cookie': 'foo=bar' + } + }); + + srv.on('upgrade', function (req, socket, head) { + assert(req.headers.cookie, 'auth header exists'); + assert.equal(req.headers.cookie, 'foo=bar'); + + ws.terminate(); + ws.on('close', function () { + srv.close(); + wss.close(); + done(); + }); + }); + }); + }); + + describe('#readyState', function() { + it('defaults to connecting', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + assert.equal(WebSocket.CONNECTING, ws.readyState); + ws.terminate(); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('set to open once connection is established', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + assert.equal(WebSocket.OPEN, ws.readyState); + srv.close(); + done(); + }); + }); + }); + + it('set to closed once connection is closed', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.close(1001); + ws.on('close', function() { + assert.equal(WebSocket.CLOSED, ws.readyState); + srv.close(); + done(); + }); + }); + }); + + it('set to closed once connection is terminated', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.terminate(); + ws.on('close', function() { + assert.equal(WebSocket.CLOSED, ws.readyState); + srv.close(); + done(); + }); + }); + }); + }); + + /* + * Ready state constants + */ + + var readyStates = { + CONNECTING: 0, + OPEN: 1, + CLOSING: 2, + CLOSED: 3 + }; + + /* + * Ready state constant tests + */ + + Object.keys(readyStates).forEach(function(state) { + describe('.' + state, function() { + it('is enumerable property of class', function() { + var propertyDescripter = Object.getOwnPropertyDescriptor(WebSocket, state) + assert.equal(readyStates[state], propertyDescripter.value); + assert.equal(true, propertyDescripter.enumerable); + }); + }); + }); + + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + Object.keys(readyStates).forEach(function(state) { + describe('.' + state, function() { + it('is property of instance', function() { + assert.equal(readyStates[state], ws[state]); + }); + }); + }); + }); + }); + + describe('events', function() { + it('emits a ping event', function(done) { + var wss = new WebSocketServer({port: ++port}); + wss.on('connection', function(client) { + client.ping(); + }); + var ws = new WebSocket('ws://localhost:' + port); + ws.on('ping', function() { + ws.terminate(); + wss.close(); + done(); + }); + }); + + it('emits a pong event', function(done) { + var wss = new WebSocketServer({port: ++port}); + wss.on('connection', function(client) { + client.pong(); + }); + var ws = new WebSocket('ws://localhost:' + port); + ws.on('pong', function() { + ws.terminate(); + wss.close(); + done(); + }); + }); + }); + + describe('connection establishing', function() { + it('can disconnect before connection is established', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.terminate(); + ws.on('open', function() { + assert.fail('connect shouldnt be raised here'); + }); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('can close before connection is established', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.close(1001); + ws.on('open', function() { + assert.fail('connect shouldnt be raised here'); + }); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('invalid server key is denied', function(done) { + server.createServer(++port, server.handlers.invalidKey, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() { + srv.close(); + done(); + }); + }); + }); + + it('close event is raised when server closes connection', function(done) { + server.createServer(++port, server.handlers.closeAfterConnect, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('close', function() { + srv.close(); + done(); + }); + }); + }); + + it('error is emitted if server aborts connection', function(done) { + server.createServer(++port, server.handlers.return401, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + assert.fail('connect shouldnt be raised here'); + }); + ws.on('error', function() { + srv.close(); + done(); + }); + }); + }); + }); + + describe('#pause and #resume', function() { + it('pauses the underlying stream', function(done) { + // this test is sort-of racecondition'y, since an unlikely slow connection + // to localhost can cause the test to succeed even when the stream pausing + // isn't working as intended. that is an extremely unlikely scenario, though + // and an acceptable risk for the test. + var client; + var serverClient; + var openCount = 0; + function onOpen() { + if (++openCount == 2) { + var paused = true; + serverClient.on('message', function() { + paused.should.not.be.ok; + wss.close(); + done(); + }); + serverClient.pause(); + setTimeout(function() { + paused = false; + serverClient.resume(); + }, 200); + client.send('foo'); + } + } + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + serverClient = ws; + serverClient.on('open', onOpen); + }); + wss.on('connection', function(ws) { + client = ws; + onOpen(); + }); + }); + }); + + describe('#ping', function() { + it('before connect should fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + try { + ws.ping(); + } + catch (e) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + + it('before connect can silently fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + ws.ping('', {}, true); + srv.close(); + ws.terminate(); + done(); + }); + }); + + it('without message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.ping(); + }); + srv.on('ping', function(message) { + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.ping('hi'); + }); + srv.on('ping', function(message) { + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with encoded message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.ping('hi', {mask: true}); + }); + srv.on('ping', function(message, flags) { + assert.ok(flags.masked); + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + }); + + describe('#pong', function() { + it('before connect should fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + try { + ws.pong(); + } + catch (e) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + + it('before connect can silently fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + ws.pong('', {}, true); + srv.close(); + ws.terminate(); + done(); + }); + }); + + it('without message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.pong(); + }); + srv.on('pong', function(message) { + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.pong('hi'); + }); + srv.on('pong', function(message) { + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with encoded message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.pong('hi', {mask: true}); + }); + srv.on('pong', function(message, flags) { + assert.ok(flags.masked); + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + }); + + describe('#send', function() { + it('very long binary data can be sent and received (with echoing server)', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var array = new Float32Array(5 * 1024 * 1024); + for (var i = 0; i < array.length; ++i) array[i] = i / 5; + ws.on('open', function() { + ws.send(array, {binary: true}); + }); + ws.on('message', function(message, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('can send and receive text data', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.send('hi'); + }); + ws.on('message', function(message, flags) { + assert.equal('hi', message); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('send and receive binary data as an array', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var array = new Float32Array(6); + for (var i = 0; i < array.length; ++i) array[i] = i / 2; + var partial = array.subarray(2, 5); + ws.on('open', function() { + ws.send(partial, {binary: true}); + }); + ws.on('message', function(message, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(partial, new Float32Array(getArrayBuffer(message)))); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('binary data can be sent and received as buffer', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var buf = new Buffer('foobar'); + ws.on('open', function() { + ws.send(buf, {binary: true}); + }); + ws.on('message', function(message, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(buf, message)); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('ArrayBuffer is auto-detected without binary flag', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var array = new Float32Array(5); + for (var i = 0; i < array.length; ++i) array[i] = i / 2; + ws.on('open', function() { + ws.send(array.buffer); + }); + ws.onmessage = function (event) { + assert.ok(event.type = 'Binary'); + assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(event.data)))); + ws.terminate(); + srv.close(); + done(); + }; + }); + }); + + it('Buffer is auto-detected without binary flag', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var buf = new Buffer('foobar'); + ws.on('open', function() { + ws.send(buf); + }); + ws.onmessage = function (event) { + assert.ok(event.type = 'Binary'); + assert.ok(areArraysEqual(event.data, buf)); + ws.terminate(); + srv.close(); + done(); + }; + }); + }); + + it('before connect should fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + try { + ws.send('hi'); + } + catch (e) { + ws.terminate(); + srv.close(); + done(); + } + }); + }); + + it('before connect should pass error through callback, if present', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + ws.send('hi', function(error) { + assert.ok(error instanceof Error); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('without data should be successful', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.send(); + }); + srv.on('message', function(message, flags) { + assert.equal('', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('calls optional callback when flushed', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.send('hi', function() { + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + }); + + it('with unencoded message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.send('hi'); + }); + srv.on('message', function(message, flags) { + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with encoded message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.send('hi', {mask: true}); + }); + srv.on('message', function(message, flags) { + assert.ok(flags.masked); + assert.equal('hi', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with unencoded binary message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var array = new Float32Array(5); + for (var i = 0; i < array.length; ++i) array[i] = i / 2; + ws.on('open', function() { + ws.send(array, {binary: true}); + }); + srv.on('message', function(message, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with encoded binary message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var array = new Float32Array(5); + for (var i = 0; i < array.length; ++i) array[i] = i / 2; + ws.on('open', function() { + ws.send(array, {mask: true, binary: true}); + }); + srv.on('message', function(message, flags) { + assert.ok(flags.binary); + assert.ok(flags.masked); + assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with binary stream will send fragmented data', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var callbackFired = false; + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.bufferSize = 100; + ws.send(fileStream, {binary: true}, function(error) { + assert.equal(null, error); + callbackFired = true; + }); + }); + srv.on('message', function(data, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile'), data)); + ws.terminate(); + }); + ws.on('close', function() { + assert.ok(callbackFired); + srv.close(); + done(); + }); + }); + }); + + it('with text stream will send fragmented data', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var callbackFired = false; + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream, {binary: false}, function(error) { + assert.equal(null, error); + callbackFired = true; + }); + }); + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + ws.terminate(); + }); + ws.on('close', function() { + assert.ok(callbackFired); + srv.close(); + done(); + }); + }); + }); + + it('will cause intermittent send to be delayed in order', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream); + ws.send('foobar'); + ws.send('baz'); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + ++receivedIndex; + if (receivedIndex == 1) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + } + else if (receivedIndex == 2) { + assert.ok(!flags.binary); + assert.equal('foobar', data); + } + else { + assert.ok(!flags.binary); + assert.equal('baz', data); + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent stream to be delayed in order', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream); + var i = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i == 1) send('foo'); + else send('bar', true); + }); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + ++receivedIndex; + if (receivedIndex == 1) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + } + else if (receivedIndex == 2) { + assert.ok(!flags.binary); + assert.equal('foobar', data); + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent ping to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream); + ws.ping('foobar'); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + srv.on('ping', function(data) { + assert.equal('foobar', data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent pong to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream); + ws.pong('foobar'); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + srv.on('pong', function(data) { + assert.equal('foobar', data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent close to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream); + ws.close(1000, 'foobar'); + }); + ws.on('close', function() { + srv.close(); + ws.terminate(); + done(); + }); + ws.on('error', function() { /* That's quite alright -- a send was attempted after close */ }); + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); + }); + srv.on('close', function(code, data) { + assert.equal(1000, code); + assert.equal('foobar', data); + }); + }); + }); + }); + + describe('#stream', function() { + it('very long binary data can be streamed', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var buffer = new Buffer(10 * 1024); + for (var i = 0; i < buffer.length; ++i) buffer[i] = i % 0xff; + ws.on('open', function() { + var i = 0; + var blockSize = 800; + var bufLen = buffer.length; + ws.stream({binary: true}, function(error, send) { + assert.ok(!error); + var start = i * blockSize; + var toSend = Math.min(blockSize, bufLen - (i * blockSize)); + var end = start + toSend; + var isFinal = toSend < blockSize; + send(buffer.slice(start, end), isFinal); + i += 1; + }); + }); + srv.on('message', function(data, flags) { + assert.ok(flags.binary); + assert.ok(areArraysEqual(buffer, data)); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('before connect should pass error through callback', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('error', function() {}); + ws.stream(function(error) { + assert.ok(error instanceof Error); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('without callback should fail', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + ws.on('open', function() { + try { + ws.stream(); + } + catch (e) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent send to be delayed in order', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + ws.on('open', function() { + var i = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i == 1) { + send(payload.substr(0, 5)); + ws.send('foobar'); + ws.send('baz'); + } + else { + send(payload.substr(5, 5), true); + } + }); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + ++receivedIndex; + if (receivedIndex == 1) { + assert.ok(!flags.binary); + assert.equal(payload, data); + } + else if (receivedIndex == 2) { + assert.ok(!flags.binary); + assert.equal('foobar', data); + } + else { + assert.ok(!flags.binary); + assert.equal('baz', data); + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent stream to be delayed in order', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + ws.on('open', function() { + var i = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i == 1) { + send(payload.substr(0, 5)); + var i2 = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i2 == 1) send('foo'); + else send('bar', true); + }); + ws.send('baz'); + } + else send(payload.substr(5, 5), true); + }); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + ++receivedIndex; + if (receivedIndex == 1) { + assert.ok(!flags.binary); + assert.equal(payload, data); + } + else if (receivedIndex == 2) { + assert.ok(!flags.binary); + assert.equal('foobar', data); + } + else if (receivedIndex == 3){ + assert.ok(!flags.binary); + assert.equal('baz', data); + setTimeout(function() { + srv.close(); + ws.terminate(); + done(); + }, 1000); + } + else throw new Error('more messages than we actually sent just arrived'); + }); + }); + }); + + it('will cause intermittent ping to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + ws.on('open', function() { + var i = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i == 1) { + send(payload.substr(0, 5)); + ws.ping('foobar'); + } + else { + send(payload.substr(5, 5), true); + } + }); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.equal(payload, data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + srv.on('ping', function(data) { + assert.equal('foobar', data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent pong to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + ws.on('open', function() { + var i = 0; + ws.stream(function(error, send) { + assert.ok(!error); + if (++i == 1) { + send(payload.substr(0, 5)); + ws.pong('foobar'); + } + else { + send(payload.substr(5, 5), true); + } + }); + }); + var receivedIndex = 0; + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.equal(payload, data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + srv.on('pong', function(data) { + assert.equal('foobar', data); + if (++receivedIndex == 2) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('will cause intermittent close to be delivered', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var payload = 'HelloWorld'; + var errorGiven = false; + ws.on('open', function() { + var i = 0; + ws.stream(function(error, send) { + if (++i == 1) { + send(payload.substr(0, 5)); + ws.close(1000, 'foobar'); + } + else if(i == 2) { + send(payload.substr(5, 5), true); + } + else if (i == 3) { + assert.ok(error); + errorGiven = true; + } + }); + }); + ws.on('close', function() { + assert.ok(errorGiven); + srv.close(); + ws.terminate(); + done(); + }); + srv.on('message', function(data, flags) { + assert.ok(!flags.binary); + assert.equal(payload, data); + }); + srv.on('close', function(code, data) { + assert.equal(1000, code); + assert.equal('foobar', data); + }); + }); + }); + }); + + describe('#close', function() { + it('will raise error callback, if any, if called during send stream', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var errorGiven = false; + ws.on('open', function() { + var fileStream = fs.createReadStream('test/fixtures/textfile'); + fileStream.setEncoding('utf8'); + fileStream.bufferSize = 100; + ws.send(fileStream, function(error) { + errorGiven = error != null; + }); + ws.close(1000, 'foobar'); + }); + ws.on('close', function() { + setTimeout(function() { + assert.ok(errorGiven); + srv.close(); + ws.terminate(); + done(); + }, 1000); + }); + }); + }); + + it('without invalid first argument throws exception', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + try { + ws.close('error'); + } + catch (e) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('without reserved error code 1004 throws exception', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + try { + ws.close(1004); + } + catch (e) { + srv.close(); + ws.terminate(); + done(); + } + }); + }); + }); + + it('without message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.close(1000); + }); + srv.on('close', function(code, message, flags) { + assert.equal('', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.close(1000, 'some reason'); + }); + srv.on('close', function(code, message, flags) { + assert.ok(flags.masked); + assert.equal('some reason', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('with encoded message is successfully transmitted to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('open', function() { + ws.close(1000, 'some reason', {mask: true}); + }); + srv.on('close', function(code, message, flags) { + assert.ok(flags.masked); + assert.equal('some reason', message); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + + it('ends connection to the server', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var connectedOnce = false; + ws.on('open', function() { + connectedOnce = true; + ws.close(1000, 'some reason', {mask: true}); + }); + ws.on('close', function() { + assert.ok(connectedOnce); + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + }); + + describe('W3C API emulation', function() { + it('should not throw errors when getting and setting', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var listener = function () {}; + + ws.onmessage = listener; + ws.onerror = listener; + ws.onclose = listener; + ws.onopen = listener; + + assert.ok(ws.onopen === listener); + assert.ok(ws.onmessage === listener); + assert.ok(ws.onclose === listener); + assert.ok(ws.onerror === listener); + + srv.close(); + ws.terminate(); + done(); + }); + }); + + it('should work the same as the EventEmitter api', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + var listener = function() {}; + var message = 0; + var close = 0; + var open = 0; + + ws.onmessage = function(messageEvent) { + assert.ok(!!messageEvent.data); + ++message; + ws.close(); + }; + + ws.onopen = function() { + ++open; + } + + ws.onclose = function() { + ++close; + } + + ws.on('open', function() { + ws.send('foo'); + }); + + ws.on('close', function() { + process.nextTick(function() { + assert.ok(message === 1); + assert.ok(open === 1); + assert.ok(close === 1); + + srv.close(); + ws.terminate(); + done(); + }); + }); + }); + }); + + it('should receive text data wrapped in a MessageEvent when using addEventListener', function(done) { + server.createServer(++port, function(srv) { + var ws = new WebSocket('ws://localhost:' + port); + ws.addEventListener('open', function() { + ws.send('hi'); + }); + ws.addEventListener('message', function(messageEvent) { + assert.equal('hi', messageEvent.data); + ws.terminate(); + srv.close(); + done(); + }); + }); + }); + + it('should receive valid CloseEvent when server closes with code 1000', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.addEventListener('close', function(closeEvent) { + assert.equal(true, closeEvent.wasClean); + assert.equal(1000, closeEvent.code); + ws.terminate(); + wss.close(); + done(); + }); + }); + wss.on('connection', function(client) { + client.close(1000); + }); + }); + + it('should receive valid CloseEvent when server closes with code 1001', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.addEventListener('close', function(closeEvent) { + assert.equal(false, closeEvent.wasClean); + assert.equal(1001, closeEvent.code); + assert.equal('some daft reason', closeEvent.reason); + ws.terminate(); + wss.close(); + done(); + }); + }); + wss.on('connection', function(client) { + client.close(1001, 'some daft reason'); + }); + }); + + it('should have target set on Events', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.addEventListener('open', function(openEvent) { + assert.equal(ws, openEvent.target); + }); + ws.addEventListener('message', function(messageEvent) { + assert.equal(ws, messageEvent.target); + wss.close(); + }); + ws.addEventListener('close', function(closeEvent) { + assert.equal(ws, closeEvent.target); + ws.emit('error', new Error('forced')); + }); + ws.addEventListener('error', function(errorEvent) { + assert.equal(errorEvent.message, 'forced'); + assert.equal(ws, errorEvent.target); + ws.terminate(); + done(); + }); + }); + wss.on('connection', function(client) { + client.send('hi') + }); + }); + }); + + describe('ssl', function() { + it('can connect to secure websocket server', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem') + }; + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + var wss = new WebSocketServer({server: app}); + app.listen(++port, function() { + var ws = new WebSocket('wss://localhost:' + port); + }); + wss.on('connection', function(ws) { + app.close(); + ws.terminate(); + wss.close(); + done(); + }); + }); + + it('can connect to secure websocket server with client side certificate', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem'), + ca: [fs.readFileSync('test/fixtures/ca1-cert.pem')], + requestCert: true + }; + var clientOptions = { + key: fs.readFileSync('test/fixtures/agent1-key.pem'), + cert: fs.readFileSync('test/fixtures/agent1-cert.pem') + }; + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + var success = false; + var wss = new WebSocketServer({ + server: app, + verifyClient: function(info) { + success = !!info.req.client.authorized; + return true; + } + }); + app.listen(++port, function() { + var ws = new WebSocket('wss://localhost:' + port, clientOptions); + }); + wss.on('connection', function(ws) { + app.close(); + ws.terminate(); + wss.close(); + success.should.be.ok; + done(); + }); + }); + + it('cannot connect to secure websocket server via ws://', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem') + }; + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + var wss = new WebSocketServer({server: app}); + app.listen(++port, function() { + var ws = new WebSocket('ws://localhost:' + port, { rejectUnauthorized :false }); + ws.on('error', function() { + app.close(); + ws.terminate(); + wss.close(); + done(); + }); + }); + }); + + it('can send and receive text data', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem') + }; + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + var wss = new WebSocketServer({server: app}); + app.listen(++port, function() { + var ws = new WebSocket('wss://localhost:' + port); + ws.on('open', function() { + ws.send('foobar'); + }); + }); + wss.on('connection', function(ws) { + ws.on('message', function(message, flags) { + message.should.eql('foobar'); + app.close(); + ws.terminate(); + wss.close(); + done(); + }); + }); + }); + + it('can send and receive very long binary data', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem') + } + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + crypto.randomBytes(5 * 1024 * 1024, function(ex, buf) { + if (ex) throw ex; + var wss = new WebSocketServer({server: app}); + app.listen(++port, function() { + var ws = new WebSocket('wss://localhost:' + port); + ws.on('open', function() { + ws.send(buf, {binary: true}); + }); + ws.on('message', function(message, flags) { + flags.binary.should.be.ok; + areArraysEqual(buf, message).should.be.ok; + app.close(); + ws.terminate(); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + ws.on('message', function(message, flags) { + ws.send(message, {binary: true}); + }); + }); + }); + }); + }); + + describe('protocol support discovery', function() { + describe('#supports', function() { + describe('#binary', function() { + it('returns true for hybi transport', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + assert.equal(true, client.supports.binary); + wss.close(); + done(); + }); + }); + + it('returns false for hixie transport', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + }); + wss.on('connection', function(client) { + assert.equal(false, client.supports.binary); + wss.close(); + done(); + }); + }); + }); + }); + }); + + describe('host and origin headers', function() { + it('includes the host header with port number', function(done) { + var srv = http.createServer(); + srv.listen(++port, function(){ + srv.on('upgrade', function(req, socket, upgradeHeade) { + assert.equal('localhost:' + port, req.headers['host']); + srv.close(); + done(); + }); + var ws = new WebSocket('ws://localhost:' + port); + }); + }); + + it('includes the origin header with port number', function(done) { + var srv = http.createServer(); + srv.listen(++port, function() { + srv.on('upgrade', function(req, socket, upgradeHeade) { + assert.equal('localhost:' + port, req.headers['origin']); + srv.close(); + done(); + }); + var ws = new WebSocket('ws://localhost:' + port); + }); + }); + }); + +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocketServer.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocketServer.test.js new file mode 100644 index 00000000..c21fd97f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocketServer.test.js @@ -0,0 +1,1103 @@ +var http = require('http') + , https = require('https') + , WebSocket = require('../') + , WebSocketServer = WebSocket.Server + , fs = require('fs') + , should = require('should'); + +var port = 8000; + +function getArrayBuffer(buf) { + var l = buf.length; + var arrayBuf = new ArrayBuffer(l); + for (var i = 0; i < l; ++i) { + arrayBuf[i] = buf[i]; + } + return arrayBuf; +} + +function areArraysEqual(x, y) { + if (x.length != y.length) return false; + for (var i = 0, l = x.length; i < l; ++i) { + if (x[i] !== y[i]) return false; + } + return true; +} + +describe('WebSocketServer', function() { + describe('#ctor', function() { + it('throws an error if no option object is passed', function() { + var gotException = false; + try { + var wss = new WebSocketServer(); + } + catch (e) { + gotException = true; + } + gotException.should.be.ok; + }); + + it('throws an error if no port or server is specified', function() { + var gotException = false; + try { + var wss = new WebSocketServer({}); + } + catch (e) { + gotException = true; + } + gotException.should.be.ok; + }); + + it('does not throw an error if no port or server is specified, when the noServer option is true', function() { + var gotException = false; + try { + var wss = new WebSocketServer({noServer: true}); + } + catch (e) { + gotException = true; + } + gotException.should.eql(false); + }); + + it('emits an error if http server bind fails', function(done) { + var wss = new WebSocketServer({port: 1}); + wss.on('error', function() { done(); }); + }); + + it('starts a server on a given port', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + wss.close(); + done(); + }); + }); + + it('uses a precreated http server', function (done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss = new WebSocketServer({server: srv}); + var ws = new WebSocket('ws://localhost:' + port); + + wss.on('connection', function(client) { + wss.close(); + srv.close(); + done(); + }); + }); + }); + + it('uses a precreated http server listening on unix socket', function (done) { + var srv = http.createServer(); + var sockPath = '/tmp/ws_socket_'+new Date().getTime()+'.'+Math.floor(Math.random() * 1000); + srv.listen(sockPath, function () { + var wss = new WebSocketServer({server: srv}); + var ws = new WebSocket('ws+unix://'+sockPath); + + wss.on('connection', function(client) { + wss.close(); + srv.close(); + done(); + }); + }); + }); + + it('emits path specific connection event', function (done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss = new WebSocketServer({server: srv}); + var ws = new WebSocket('ws://localhost:' + port+'/endpointName'); + + wss.on('connection/endpointName', function(client) { + wss.close(); + srv.close(); + done(); + }); + }); + }); + + it('can have two different instances listening on the same http server with two different paths', function(done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss1 = new WebSocketServer({server: srv, path: '/wss1'}) + , wss2 = new WebSocketServer({server: srv, path: '/wss2'}); + var doneCount = 0; + wss1.on('connection', function(client) { + wss1.close(); + if (++doneCount == 2) { + srv.close(); + done(); + } + }); + wss2.on('connection', function(client) { + wss2.close(); + if (++doneCount == 2) { + srv.close(); + done(); + } + }); + var ws1 = new WebSocket('ws://localhost:' + port + '/wss1'); + var ws2 = new WebSocket('ws://localhost:' + port + '/wss2?foo=1'); + }); + }); + + it('cannot have two different instances listening on the same http server with the same path', function(done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss1 = new WebSocketServer({server: srv, path: '/wss1'}); + try { + var wss2 = new WebSocketServer({server: srv, path: '/wss1'}); + } + catch (e) { + wss1.close(); + srv.close(); + done(); + } + }); + }); + }); + + describe('#close', function() { + it('will close all clients', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('close', function() { + if (++closes == 2) done(); + }); + }); + var closes = 0; + wss.on('connection', function(client) { + client.on('close', function() { + if (++closes == 2) done(); + }); + wss.close(); + }); + }); + + it('does not close a precreated server', function(done) { + var srv = http.createServer(); + var realClose = srv.close; + srv.close = function() { + should.fail('must not close pre-created server'); + } + srv.listen(++port, function () { + var wss = new WebSocketServer({server: srv}); + var ws = new WebSocket('ws://localhost:' + port); + wss.on('connection', function(client) { + wss.close(); + srv.close = realClose; + srv.close(); + done(); + }); + }); + }); + + it('cleans up websocket data on a precreated server', function(done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss1 = new WebSocketServer({server: srv, path: '/wss1'}) + , wss2 = new WebSocketServer({server: srv, path: '/wss2'}); + (typeof srv._webSocketPaths).should.eql('object'); + Object.keys(srv._webSocketPaths).length.should.eql(2); + wss1.close(); + Object.keys(srv._webSocketPaths).length.should.eql(1); + wss2.close(); + (typeof srv._webSocketPaths).should.eql('undefined'); + srv.close(); + done(); + }); + }); + }); + + describe('#clients', function() { + it('returns a list of connected clients', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + wss.clients.length.should.eql(0); + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + wss.clients.length.should.eql(1); + wss.close(); + done(); + }); + }); + + it('can be disabled', function(done) { + var wss = new WebSocketServer({port: ++port, clientTracking: false}, function() { + wss.clients.length.should.eql(0); + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + wss.clients.length.should.eql(0); + wss.close(); + done(); + }); + }); + + it('is updated when client terminates the connection', function(done) { + var ws; + var wss = new WebSocketServer({port: ++port}, function() { + ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + client.on('close', function() { + wss.clients.length.should.eql(0); + wss.close(); + done(); + }); + ws.terminate(); + }); + }); + + it('is updated when client closes the connection', function(done) { + var ws; + var wss = new WebSocketServer({port: ++port}, function() { + ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(client) { + client.on('close', function() { + wss.clients.length.should.eql(0); + wss.close(); + done(); + }); + ws.close(); + }); + }); + }); + + describe('#options', function() { + it('exposes options passed to constructor', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + wss.options.port.should.eql(port); + wss.close(); + done(); + }); + }); + }); + + describe('#handleUpgrade', function() { + it('can be used for a pre-existing server', function (done) { + var srv = http.createServer(); + srv.listen(++port, function () { + var wss = new WebSocketServer({noServer: true}); + srv.on('upgrade', function(req, socket, upgradeHead) { + wss.handleUpgrade(req, socket, upgradeHead, function(client) { + client.send('hello'); + }); + }); + var ws = new WebSocket('ws://localhost:' + port); + ws.on('message', function(message) { + message.should.eql('hello'); + wss.close(); + srv.close(); + done(); + }); + }); + }); + }); + + describe('hybi mode', function() { + describe('connection establishing', function() { + it('does not accept connections with no sec-websocket-key', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(400); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('does not accept connections with no sec-websocket-version', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(400); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('does not accept connections with invalid sec-websocket-version', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 12 + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(400); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('client can be denied', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 8, + 'Sec-WebSocket-Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(401); + process.nextTick(function() { + wss.close(); + done(); + }); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('client can be accepted', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return true; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.end(); + }); + wss.on('connection', function(ws) { + ws.terminate(); + wss.close(); + done(); + }); + wss.on('error', function() {}); + }); + + it('verifyClient gets client origin', function(done) { + var verifyClientCalled = false; + var wss = new WebSocketServer({port: ++port, verifyClient: function(info) { + info.origin.should.eql('http://foobarbaz.com'); + verifyClientCalled = true; + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Origin': 'http://foobarbaz.com' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + verifyClientCalled.should.be.ok; + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + + it('verifyClient gets original request', function(done) { + var verifyClientCalled = false; + var wss = new WebSocketServer({port: ++port, verifyClient: function(info) { + info.req.headers['sec-websocket-key'].should.eql('dGhlIHNhbXBsZSBub25jZQ=='); + verifyClientCalled = true; + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Origin': 'http://foobarbaz.com' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + verifyClientCalled.should.be.ok; + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + + it('verifyClient has secure:true for ssl connections', function(done) { + var options = { + key: fs.readFileSync('test/fixtures/key.pem'), + cert: fs.readFileSync('test/fixtures/certificate.pem') + }; + var app = https.createServer(options, function (req, res) { + res.writeHead(200); + res.end(); + }); + var success = false; + var wss = new WebSocketServer({ + server: app, + verifyClient: function(info) { + success = info.secure === true; + return true; + } + }); + app.listen(++port, function() { + var ws = new WebSocket('wss://localhost:' + port); + }); + wss.on('connection', function(ws) { + app.close(); + ws.terminate(); + wss.close(); + success.should.be.ok; + done(); + }); + }); + + it('verifyClient has secure:false for non-ssl connections', function(done) { + var app = http.createServer(function (req, res) { + res.writeHead(200); + res.end(); + }); + var success = false; + var wss = new WebSocketServer({ + server: app, + verifyClient: function(info) { + success = info.secure === false; + return true; + } + }); + app.listen(++port, function() { + var ws = new WebSocket('ws://localhost:' + port); + }); + wss.on('connection', function(ws) { + app.close(); + ws.terminate(); + wss.close(); + success.should.be.ok; + done(); + }); + }); + + it('client can be denied asynchronously', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) { + process.nextTick(function() { + cb(false); + }); + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 8, + 'Sec-WebSocket-Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(401); + process.nextTick(function() { + wss.close(); + done(); + }); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('client can be accepted asynchronously', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) { + process.nextTick(function() { + cb(true); + }); + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.end(); + }); + wss.on('connection', function(ws) { + ws.terminate(); + wss.close(); + done(); + }); + wss.on('error', function() {}); + }); + + it('handles messages passed along with the upgrade request (upgrade head)', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return true; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.write(new Buffer([0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f], 'binary')); + req.end(); + }); + wss.on('connection', function(ws) { + ws.on('message', function(data) { + data.should.eql('Hello'); + ws.terminate(); + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + + it('selects the first protocol by default', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'}); + ws.on('open', function(client) { + ws.protocol.should.eql('prot1'); + wss.close(); + done(); + }); + }); + }); + + it('selects the last protocol via protocol handler', function(done) { + var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) { + cb(true, ps[ps.length-1]); }}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'}); + ws.on('open', function(client) { + ws.protocol.should.eql('prot2'); + wss.close(); + done(); + }); + }); + }); + + it('client detects invalid server protocol', function(done) { + var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) { + cb(true, 'prot3'); }}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'}); + ws.on('open', function(client) { + done(new Error('connection must not be established')); + }); + ws.on('error', function() { + done(); + }); + }); + }); + + it('client detects no server protocol', function(done) { + var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) { + cb(true); }}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'}); + ws.on('open', function(client) { + done(new Error('connection must not be established')); + }); + ws.on('error', function() { + done(); + }); + }); + }); + + it('client refuses server protocols', function(done) { + var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) { + cb(false); }}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'}); + ws.on('open', function(client) { + done(new Error('connection must not be established')); + }); + ws.on('error', function() { + done(); + }); + }); + }); + + it('server detects invalid protocol handler', function(done) { + var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) { + // not calling callback is an error and shouldn't timeout + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': 13, + 'Sec-WebSocket-Origin': 'http://foobar.com' + } + }; + options.port = port; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(501); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + }); + + describe('messaging', function() { + it('can send and receive data', function(done) { + var data = new Array(65*1024); + for (var i = 0; i < data.length; ++i) { + data[i] = String.fromCharCode(65 + ~~(25 * Math.random())); + } + data = data.join(''); + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port); + ws.on('message', function(message, flags) { + ws.send(message); + }); + }); + wss.on('connection', function(client) { + client.on('message', function(message) { + message.should.eql(data); + wss.close(); + done(); + }); + client.send(data); + }); + }); + }); + }); + + describe('hixie mode', function() { + it('can be disabled', function(done) { + var wss = new WebSocketServer({port: ++port, disableHixie: true}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(401); + process.nextTick(function() { + wss.close(); + done(); + }); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + describe('connection establishing', function() { + it('does not accept connections with no sec-websocket-key1', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(400); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('does not accept connections with no sec-websocket-key2', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(400); + wss.close(); + done(); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('accepts connections with valid handshake', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + }); + wss.on('connection', function(ws) { + ws.terminate(); + wss.close(); + done(); + }); + wss.on('error', function() {}); + }); + + it('client can be denied', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(401); + process.nextTick(function() { + wss.close(); + done(); + }); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('client can be accepted', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return true; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + }); + wss.on('connection', function(ws) { + ws.terminate(); + wss.close(); + done(); + }); + wss.on('error', function() {}); + }); + + it('verifyClient gets client origin', function(done) { + var verifyClientCalled = false; + var wss = new WebSocketServer({port: ++port, verifyClient: function(info) { + info.origin.should.eql('http://foobarbaz.com'); + verifyClientCalled = true; + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Origin': 'http://foobarbaz.com', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + req.on('response', function(res) { + verifyClientCalled.should.be.ok; + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + + it('verifyClient gets original request', function(done) { + var verifyClientCalled = false; + var wss = new WebSocketServer({port: ++port, verifyClient: function(info) { + info.req.headers['sec-websocket-key1'].should.eql('3e6b263 4 17 80'); + verifyClientCalled = true; + return false; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Origin': 'http://foobarbaz.com', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + req.on('response', function(res) { + verifyClientCalled.should.be.ok; + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + + it('client can be denied asynchronously', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) { + cb(false); + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Origin': 'http://foobarbaz.com', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + req.on('response', function(res) { + res.statusCode.should.eql(401); + process.nextTick(function() { + wss.close(); + done(); + }); + }); + }); + wss.on('connection', function(ws) { + done(new Error('connection must not be established')); + }); + wss.on('error', function() {}); + }); + + it('client can be accepted asynchronously', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) { + cb(true); + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Origin': 'http://foobarbaz.com', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.end(); + }); + wss.on('connection', function(ws) { + wss.close(); + done(); + }); + wss.on('error', function() {}); + }); + + it('handles messages passed along with the upgrade request (upgrade head)', function(done) { + var wss = new WebSocketServer({port: ++port, verifyClient: function(o) { + return true; + }}, function() { + var options = { + port: port, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'WebSocket', + 'Sec-WebSocket-Key1': '3e6b263 4 17 80', + 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90', + 'Origin': 'http://foobar.com' + } + }; + var req = http.request(options); + req.write('WjN}|M(6'); + req.write(new Buffer([0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff], 'binary')); + req.end(); + }); + wss.on('connection', function(ws) { + ws.on('message', function(data) { + data.should.eql('Hello'); + ws.terminate(); + wss.close(); + done(); + }); + }); + wss.on('error', function() {}); + }); + }); + }); + + describe('client properties', function() { + it('protocol is exposed', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocol: 'hi'}); + }); + wss.on('connection', function(client) { + client.protocol.should.eql('hi'); + wss.close(); + done(); + }); + }); + + it('protocolVersion is exposed', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocolVersion: 8}); + }); + wss.on('connection', function(client) { + client.protocolVersion.should.eql(8); + wss.close(); + done(); + }); + }); + + it('upgradeReq is the original request object', function(done) { + var wss = new WebSocketServer({port: ++port}, function() { + var ws = new WebSocket('ws://localhost:' + port, {protocolVersion: 8}); + }); + wss.on('connection', function(client) { + client.upgradeReq.httpVersion.should.eql('1.1'); + wss.close(); + done(); + }); + }); + }); + +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/autobahn-server.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/autobahn-server.js new file mode 100644 index 00000000..36fe0c24 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/autobahn-server.js @@ -0,0 +1,29 @@ +var WebSocketServer = require('../').Server; + +process.on('uncaughtException', function(err) { + console.log('Caught exception: ', err, err.stack); +}); + +process.on('SIGINT', function () { + try { + console.log('Updating reports and shutting down'); + var ws = new WebSocket('ws://localhost:9001/updateReports?agent=ws'); + ws.on('close', function() { + process.exit(); + }); + } + catch(e) { + process.exit(); + } +}); + +var wss = new WebSocketServer({port: 8181}); +wss.on('connection', function(ws) { + console.log('new connection'); + ws.on('message', function(data, flags) { + ws.send(flags.buffer, {binary: flags.binary === true}); + }); + ws.on('error', function() { + console.log('error', arguments); + }); +}); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/autobahn.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/autobahn.js new file mode 100644 index 00000000..048cc904 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/autobahn.js @@ -0,0 +1,52 @@ +var WebSocket = require('../'); +var currentTest = 1; +var lastTest = -1; +var testCount = null; + +process.on('uncaughtException', function(err) { + console.log('Caught exception: ', err, err.stack); +}); + +process.on('SIGINT', function () { + try { + console.log('Updating reports and shutting down'); + var ws = new WebSocket('ws://localhost:9001/updateReports?agent=ws'); + ws.on('close', function() { + process.exit(); + }); + } + catch(e) { + process.exit(); + } +}); + +function nextTest() { + if (currentTest > testCount || (lastTest != -1 && currentTest > lastTest)) { + console.log('Updating reports and shutting down'); + var ws = new WebSocket('ws://localhost:9001/updateReports?agent=ws'); + ws.on('close', function() { + process.exit(); + }); + return; + }; + console.log('Running test case ' + currentTest + '/' + testCount); + var ws = new WebSocket('ws://localhost:9001/runCase?case=' + currentTest + '&agent=ws'); + ws.on('message', function(data, flags) { + ws.send(flags.buffer, {binary: flags.binary === true, mask: true}); + }); + ws.on('close', function(data) { + currentTest += 1; + process.nextTick(nextTest); + }); + ws.on('error', function(e) {}); +} + +var ws = new WebSocket('ws://localhost:9001/getCaseCount'); +ws.on('message', function(data, flags) { + testCount = parseInt(data); +}); +ws.on('close', function() { + if (testCount > 0) { + nextTest(); + } +}); \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/agent1-cert.pem b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/agent1-cert.pem new file mode 100644 index 00000000..cccb9fb4 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/agent1-cert.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICbjCCAdcCCQCVvok5oeLpqzANBgkqhkiG9w0BAQUFADB6MQswCQYDVQQGEwJV +UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO +BgNVBAsTB05vZGUuanMxDDAKBgNVBAMTA2NhMTEgMB4GCSqGSIb3DQEJARYRcnlA +dGlueWNsb3Vkcy5vcmcwHhcNMTMwMzA4MDAzMDIyWhcNNDAwNzIzMDAzMDIyWjB9 +MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQK +EwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MTEgMB4G +CSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwgZ8wDQYJKoZIhvcNAQEBBQAD +gY0AMIGJAoGBAL6GwKosYb0Yc3Qo0OtQVlCJ4208Idw11ij+t2W5sfYbCil5tyQo +jnhGM1CJhEXynQpXXwjKJuIeTQCkeUibTyFKa0bs8+li2FiGoKYbb4G81ovnqkmE +2iDVb8Gw3rrM4zeZ0ZdFnjMsAZac8h6+C4sB/pS9BiMOo6qTl15RQlcJAgMBAAEw +DQYJKoZIhvcNAQEFBQADgYEAOtmLo8DwTPnI4wfQbQ3hWlTS/9itww6IsxH2ODt9 +ggB7wi7N3uAdIWRZ54ke0NEAO5CW1xNTwsWcxQbiHrDOqX1vfVCjIenI76jVEEap +/Ay53ydHNBKdsKkib61Me14Mu0bA3lUul57VXwmH4NUEFB3w973Q60PschUhOEXj +7DY= +-----END CERTIFICATE----- diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/agent1-key.pem b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/agent1-key.pem new file mode 100644 index 00000000..cbd5f0c2 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/agent1-key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC+hsCqLGG9GHN0KNDrUFZQieNtPCHcNdYo/rdlubH2Gwopebck +KI54RjNQiYRF8p0KV18IyibiHk0ApHlIm08hSmtG7PPpYthYhqCmG2+BvNaL56pJ +hNog1W/BsN66zOM3mdGXRZ4zLAGWnPIevguLAf6UvQYjDqOqk5deUUJXCQIDAQAB +AoGANu/CBA+SCyVOvRK70u4yRTzNMAUjukxnuSBhH1rg/pajYnwvG6T6F6IeT72n +P0gKkh3JUE6B0bds+p9yPUZTFUXghxjcF33wlIY44H6gFE4K5WutsFJ9c450wtuu +8rXZTsIg7lAXWjTFVmdtOEPetcGlO2Hpi1O7ZzkzHgB2w9ECQQDksCCYx78or1zY +ZSokm8jmpIjG3VLKdvI9HAoJRN40ldnwFoigrFa1AHwsFtWNe8bKyVRPDoLDUjpB +dkPWgweVAkEA1UfgqguQ2KIkbtp9nDBionu3QaajksrRHwIa8vdfRfLxszfHk2fh +NGY3dkRZF8HUAbzYLrd9poVhCBAEjWekpQJASOM6AHfpnXYHCZF01SYx6hEW5wsz +kARJQODm8f1ZNTlttO/5q/xBxn7ZFNRSTD3fJlL05B2j380ddC/Vf1FT4QJAP1BC +GliqnBSuGhZUWYxni3KMeTm9rzL0F29pjpzutHYlWB2D6ndY/FQnvL0XcZ0Bka58 +womIDGnl3x3aLBwLXQJBAJv6h5CHbXHx7VyDJAcNfppAqZGcEaiVg8yf2F33iWy2 +FLthhJucx7df7SO2aw5h06bRDRAhb9br0R9/3mLr7RE= +-----END RSA PRIVATE KEY----- diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/ca1-cert.pem b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/ca1-cert.pem new file mode 100644 index 00000000..1d0c0d68 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/ca1-cert.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICazCCAdQCCQC9/g69HtxXRzANBgkqhkiG9w0BAQUFADB6MQswCQYDVQQGEwJV +UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO +BgNVBAsTB05vZGUuanMxDDAKBgNVBAMTA2NhMTEgMB4GCSqGSIb3DQEJARYRcnlA +dGlueWNsb3Vkcy5vcmcwHhcNMTMwMzA4MDAzMDIyWhcNNDAwNzIzMDAzMDIyWjB6 +MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQK +EwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDDAKBgNVBAMTA2NhMTEgMB4GCSqG +SIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0A +MIGJAoGBAKxr1mARUcv7zaqx5y4AxJPK6c1jdbSg7StcL4vg8klaPAlfNO6o+/Cl +w5CdQD3ukaVUwUOJ4T/+b3Xf7785XcWBC33GdjVQkfbHATJYcka7j7JDw3qev5Jk +1rAbRw48hF6rYlSGcx1mccAjoLoa3I8jgxCNAYHIjUQXgdmU893rAgMBAAEwDQYJ +KoZIhvcNAQEFBQADgYEAis05yxjCtJRuv8uX/DK6TX/j9C9Lzp1rKDNFTaTZ0iRw +KCw1EcNx4OXSj9gNblW4PWxpDvygrt1AmH9h2cb8K859NSHa9JOBFw6MA5C2A4Sj +NQfNATqUl4T6cdORlcDEZwHtT8b6D4A6Er31G/eJF4Sen0TUFpjdjd+l9RBjHlo= +-----END CERTIFICATE----- diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/ca1-key.pem b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/ca1-key.pem new file mode 100644 index 00000000..df149508 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/ca1-key.pem @@ -0,0 +1,17 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIFeWxJE1BrRECAggA +MBQGCCqGSIb3DQMHBAgu9PlMSQ+BOASCAoDEZN2tX0xWo/N+Jg+PrvCrFDk3P+3x +5xG/PEDjtMCAWPBEwbnaYHDzYmhNcAmxzGqEHGMDiWYs46LbO560VS3uMvFbEWPo +KYYVb13vkxl2poXdonCb5cHZA5GUYzTIVVJFptl4LHwBczHoMHtA4FqAhKlYvlWw +EOrdLB8XcwMmGPFabbbGxno0+EWWM27uNjlogfoxj35mQqSW4rOlhZ460XjOB1Zx +LjXMuZeONojkGYQRG5EUMchBoctQpCOM6cAi9r1B9BvtFCBpDV1c1zEZBzTEUd8o +kLn6tjLmY+QpTdylFjEWc7U3ppLY/pkoTBv4r85a2sEMWqkhSJboLaTboWzDJcU3 +Ke61pMpovt/3yCUd3TKgwduVwwQtDVTlBe0p66aN9QVj3CrFy/bKAGO3vxlli24H +aIjZf+OVoBY21ESlW3jLvNlBf7Ezf///2E7j4SCDLyZSFMTpFoAG/jDRyvi+wTKX +Kh485Bptnip6DCSuoH4u2SkOqwz3gJS/6s02YKe4m311QT4Pzne5/FwOFaS/HhQg +Xvyh2/d00OgJ0Y0PYQsHILPRgTUCKUXvj1O58opn3fxSacsPxIXwj6Z4FYAjUTaV +2B85k1lpant/JJEilDqMjqzx4pHZ/Z3Uto1lSM1JZs9SNL/0UR+6F0TXZTULVU9V +w8jYzz4sPr7LEyrrTbzmjQgnQFVbhAN/eKgRZK/SpLjxpmBV5MfpbPKsPUZqT4UC +4nXa8a/NYUQ9e+QKK8enq9E599c2W442W7Z1uFRZTWReMx/lF8wwA6G8zOPG0bdj +d+T5Gegzd5mvRiXMBklCo8RLxOOvgxun1n3PY4a63aH6mqBhdfhiLp5j +-----END ENCRYPTED PRIVATE KEY----- diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/certificate.pem b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/certificate.pem new file mode 100644 index 00000000..0efc2ef5 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/certificate.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICATCCAWoCCQDPufXH86n2QzANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJu +bzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTEyMDEwMTE0NDQwMFoXDTIwMDMxOTE0NDQwMFowRTELMAkG +A1UEBhMCbm8xEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtrQ7 ++r//2iV/B6F+4boH0XqFn7alcV9lpjvAmwRXNKnxAoa0f97AjYPGNLKrjpkNXXhB +JROIdbRbZnCNeC5fzX1a+JCo7KStzBXuGSZr27TtFmcV4H+9gIRIcNHtZmJLnxbJ +sIhkGR8yVYdmJZe4eT5ldk1zoB1adgPF1hZhCBMCAwEAATANBgkqhkiG9w0BAQUF +AAOBgQCeWBEHYJ4mCB5McwSSUox0T+/mJ4W48L/ZUE4LtRhHasU9hiW92xZkTa7E +QLcoJKQiWfiLX2ysAro0NX4+V8iqLziMqvswnPzz5nezaOLE/9U/QvH3l8qqNkXu +rNbsW1h/IO6FV8avWFYVFoutUwOaZ809k7iMh2F2JMgXQ5EymQ== +-----END CERTIFICATE----- diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/key.pem b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/key.pem new file mode 100644 index 00000000..176fe320 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC2tDv6v//aJX8HoX7hugfReoWftqVxX2WmO8CbBFc0qfEChrR/ +3sCNg8Y0squOmQ1deEElE4h1tFtmcI14Ll/NfVr4kKjspK3MFe4ZJmvbtO0WZxXg +f72AhEhw0e1mYkufFsmwiGQZHzJVh2Yll7h5PmV2TXOgHVp2A8XWFmEIEwIDAQAB +AoGAAlVY8sHi/aE+9xT77twWX3mGHV0SzdjfDnly40fx6S1Gc7bOtVdd9DC7pk6l +3ENeJVR02IlgU8iC5lMHq4JEHPE272jtPrLlrpWLTGmHEqoVFv9AITPqUDLhB9Kk +Hjl7h8NYBKbr2JHKICr3DIPKOT+RnXVb1PD4EORbJ3ooYmkCQQDfknUnVxPgxUGs +ouABw1WJIOVgcCY/IFt4Ihf6VWTsxBgzTJKxn3HtgvE0oqTH7V480XoH0QxHhjLq +DrgobWU9AkEA0TRJ8/ouXGnFEPAXjWr9GdPQRZ1Use2MrFjneH2+Sxc0CmYtwwqL +Kr5kS6mqJrxprJeluSjBd+3/ElxURrEXjwJAUvmlN1OPEhXDmRHd92mKnlkyKEeX +OkiFCiIFKih1S5Y/sRJTQ0781nyJjtJqO7UyC3pnQu1oFEePL+UEniRztQJAMfav +AtnpYKDSM+1jcp7uu9BemYGtzKDTTAYfoiNF42EzSJiGrWJDQn4eLgPjY0T0aAf/ +yGz3Z9ErbhMm/Ysl+QJBAL4kBxRT8gM4ByJw4sdOvSeCCANFq8fhbgm8pGWlCPb5 +JGmX3/GHFM8x2tbWMGpyZP1DLtiNEFz7eCGktWK5rqE= +-----END RSA PRIVATE KEY----- diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/request.pem b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/request.pem new file mode 100644 index 00000000..51bc7f62 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/request.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBhDCB7gIBADBFMQswCQYDVQQGEwJubzETMBEGA1UECAwKU29tZS1TdGF0ZTEh +MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQC2tDv6v//aJX8HoX7hugfReoWftqVxX2WmO8CbBFc0qfEC +hrR/3sCNg8Y0squOmQ1deEElE4h1tFtmcI14Ll/NfVr4kKjspK3MFe4ZJmvbtO0W +ZxXgf72AhEhw0e1mYkufFsmwiGQZHzJVh2Yll7h5PmV2TXOgHVp2A8XWFmEIEwID +AQABoAAwDQYJKoZIhvcNAQEFBQADgYEAjsUXEARgfxZNkMjuUcudgU2w4JXS0gGI +JQ0U1LmU0vMDSKwqndMlvCbKzEgPbJnGJDI8D4MeINCJHa5Ceyb8c+jaJYUcCabl +lQW5Psn3+eWp8ncKlIycDRj1Qk615XuXtV0fhkrgQM2ZCm9LaQ1O1Gd/CzLihLjF +W0MmgMKMMRk= +-----END CERTIFICATE REQUEST----- diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/textfile b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/textfile new file mode 100644 index 00000000..a10483b0 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/textfile @@ -0,0 +1,9 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam egestas, massa at aliquam luctus, sapien erat viverra elit, nec pulvinar turpis eros sagittis urna. Pellentesque imperdiet tempor varius. Pellentesque blandit, ipsum in imperdiet venenatis, mi elit faucibus odio, id condimentum ante enim sed lectus. Aliquam et odio non odio pellentesque pulvinar. Vestibulum a erat dolor. Integer pretium risus sit amet nisl volutpat nec venenatis magna egestas. Ut bibendum felis eu tellus laoreet eleifend. Nam pulvinar auctor tortor, eu iaculis leo vestibulum quis. In euismod risus ac purus vehicula et fermentum ligula consectetur. Vivamus condimentum tempus lacinia. + +Curabitur sodales condimentum urna id dictum. Sed quis justo sit amet quam ultrices tincidunt vel laoreet nulla. Nullam quis ipsum sed nisi mollis bibendum at sit amet nisi. Donec laoreet consequat velit sit amet mollis. Nam sed sapien a massa iaculis dapibus. Sed dui nunc, ultricies et pellentesque ullamcorper, aliquet vitae ligula. Integer eu velit in neque iaculis venenatis. Ut rhoncus cursus est, ac dignissim leo vehicula a. Nulla ullamcorper vulputate mauris id blandit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque eleifend, nisi a tempor sollicitudin, odio massa pretium urna, quis congue sapien elit at tortor. Curabitur ipsum orci, vehicula non commodo molestie, laoreet id enim. Pellentesque convallis ultrices congue. Pellentesque nec iaculis lorem. In sagittis pharetra ipsum eget sodales. + +Fusce id nulla odio. Nunc nibh justo, placerat vel tincidunt sed, ornare et enim. Nulla vel urna vel ante commodo bibendum in vitae metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis erat nunc, semper eget sagittis sit amet, ullamcorper eget lacus. Donec hendrerit ipsum vitae eros vestibulum eu gravida neque tincidunt. Ut molestie lacinia nulla. Donec mattis odio at magna egestas at pellentesque eros accumsan. Praesent interdum sem sit amet nibh commodo dignissim. Duis laoreet, enim ultricies fringilla suscipit, enim libero cursus nulla, sollicitudin adipiscing erat velit ut dui. Nulla eleifend mauris at velit fringilla a molestie lorem venenatis. + +Donec sit amet scelerisque metus. Cras ac felis a nulla venenatis vulputate. Duis porttitor eros ac neque rhoncus eget aliquet neque egestas. Quisque sed nunc est, vitae dapibus quam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In vehicula, est vitae posuere ultricies, diam purus pretium sapien, nec rhoncus dolor nisl eget arcu. Aliquam et nisi vitae risus tincidunt auctor. In vehicula, erat a cursus adipiscing, lorem orci congue est, nec ultricies elit dui in nunc. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +Duis congue tempus elit sit amet auctor. Duis dignissim, risus ut sollicitudin ultricies, dolor ligula gravida odio, nec congue orci purus ut ligula. Fusce pretium dictum lectus at volutpat. Sed non auctor mauris. Etiam placerat vestibulum massa id blandit. Quisque consequat lacus ut nulla euismod facilisis. Sed aliquet ipsum nec mi imperdiet viverra. Pellentesque ullamcorper, lectus nec varius gravida, odio justo cursus risus, eu sagittis metus arcu quis felis. Phasellus consectetur vehicula libero, at condimentum orci euismod vel. Nunc purus tortor, suscipit nec fringilla nec, vulputate et nibh. Nam porta vehicula neque. Praesent porttitor, sapien eu auctor euismod, arcu quam elementum urna, sed hendrerit magna augue sed quam. \ No newline at end of file diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/hybi-common.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/hybi-common.js new file mode 100644 index 00000000..006f9c69 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/hybi-common.js @@ -0,0 +1,99 @@ +/** + * Returns a Buffer from a "ff 00 ff"-type hex string. + */ + +getBufferFromHexString = function(byteStr) { + var bytes = byteStr.split(' '); + var buf = new Buffer(bytes.length); + for (var i = 0; i < bytes.length; ++i) { + buf[i] = parseInt(bytes[i], 16); + } + return buf; +} + +/** + * Returns a hex string from a Buffer. + */ + +getHexStringFromBuffer = function(data) { + var s = ''; + for (var i = 0; i < data.length; ++i) { + s += padl(data[i].toString(16), 2, '0') + ' '; + } + return s.trim(); +} + +/** + * Splits a buffer in two parts. + */ + +splitBuffer = function(buffer) { + var b1 = new Buffer(Math.ceil(buffer.length / 2)); + buffer.copy(b1, 0, 0, b1.length); + var b2 = new Buffer(Math.floor(buffer.length / 2)); + buffer.copy(b2, 0, b1.length, b1.length + b2.length); + return [b1, b2]; +} + +/** + * Performs hybi07+ type masking on a hex string or buffer. + */ + +mask = function(buf, maskString) { + if (typeof buf == 'string') buf = new Buffer(buf); + var mask = getBufferFromHexString(maskString || '34 83 a8 68'); + for (var i = 0; i < buf.length; ++i) { + buf[i] ^= mask[i % 4]; + } + return buf; +} + +/** + * Returns a hex string representing the length of a message + */ + +getHybiLengthAsHexString = function(len, masked) { + if (len < 126) { + var buf = new Buffer(1); + buf[0] = (masked ? 0x80 : 0) | len; + } + else if (len < 65536) { + var buf = new Buffer(3); + buf[0] = (masked ? 0x80 : 0) | 126; + getBufferFromHexString(pack(4, len)).copy(buf, 1); + } + else { + var buf = new Buffer(9); + buf[0] = (masked ? 0x80 : 0) | 127; + getBufferFromHexString(pack(16, len)).copy(buf, 1); + } + return getHexStringFromBuffer(buf); +} + +/** + * Unpacks a Buffer into a number. + */ + +unpack = function(buffer) { + var n = 0; + for (var i = 0; i < buffer.length; ++i) { + n = (i == 0) ? buffer[i] : (n * 256) + buffer[i]; + } + return n; +} + +/** + * Returns a hex string, representing a specific byte count 'length', from a number. + */ + +pack = function(length, number) { + return padl(number.toString(16), length, '0').replace(/([0-9a-f][0-9a-f])/gi, '$1 ').trim(); +} + +/** + * Left pads the string 's' to a total length of 'n' with char 'c'. + */ + +padl = function(s, n, c) { + return new Array(1 + n - s.length).join(c) + s; +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/testserver.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/testserver.js new file mode 100644 index 00000000..3e7a9667 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/testserver.js @@ -0,0 +1,180 @@ +var http = require('http') + , util = require('util') + , crypto = require('crypto') + , events = require('events') + , Sender = require('../lib/Sender') + , Receiver = require('../lib/Receiver'); + +module.exports = { + handlers: { + valid: validServer, + invalidKey: invalidRequestHandler, + closeAfterConnect: closeAfterConnectHandler, + return401: return401 + }, + createServer: function(port, handler, cb) { + if (handler && !cb) { + cb = handler; + handler = null; + } + var webServer = http.createServer(function (req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('okay'); + }); + var srv = new Server(webServer); + webServer.on('upgrade', function(req, socket) { + webServer._socket = socket; + (handler || validServer)(srv, req, socket); + }); + webServer.listen(port, '127.0.0.1', function() { cb(srv); }); + } +}; + +/** + * Test strategies + */ + +function validServer(server, req, socket) { + if (typeof req.headers.upgrade === 'undefined' || + req.headers.upgrade.toLowerCase() !== 'websocket') { + throw new Error('invalid headers'); + return; + } + + if (!req.headers['sec-websocket-key']) { + socket.end(); + throw new Error('websocket key is missing'); + } + + // calc key + var key = req.headers['sec-websocket-key']; + var shasum = crypto.createHash('sha1'); + shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + key = shasum.digest('base64'); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: websocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Accept: ' + key + ]; + + socket.write(headers.concat('', '').join('\r\n')); + socket.setTimeout(0); + socket.setNoDelay(true); + + var sender = new Sender(socket); + var receiver = new Receiver(); + receiver.ontext = function (message, flags) { + server.emit('message', message, flags); + sender.send(message); + }; + receiver.onbinary = function (message, flags) { + flags = flags || {}; + flags.binary = true; + server.emit('message', message, flags); + sender.send(message, {binary: true}); + }; + receiver.onping = function (message, flags) { + flags = flags || {}; + server.emit('ping', message, flags); + }; + receiver.onpong = function (message, flags) { + flags = flags || {}; + server.emit('pong', message, flags); + }; + receiver.onclose = function (code, message, flags) { + flags = flags || {}; + server.emit('close', code, message, flags); + }; + socket.on('data', function (data) { + receiver.add(data); + }); + socket.on('end', function() { + socket.end(); + }); +} + +function invalidRequestHandler(server, req, socket) { + if (typeof req.headers.upgrade === 'undefined' || + req.headers.upgrade.toLowerCase() !== 'websocket') { + throw new Error('invalid headers'); + return; + } + + if (!req.headers['sec-websocket-key']) { + socket.end(); + throw new Error('websocket key is missing'); + } + + // calc key + var key = req.headers['sec-websocket-key']; + var shasum = crypto.createHash('sha1'); + shasum.update(key + "bogus"); + key = shasum.digest('base64'); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: websocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Accept: ' + key + ]; + + socket.write(headers.concat('', '').join('\r\n')); + socket.end(); +} + +function closeAfterConnectHandler(server, req, socket) { + if (typeof req.headers.upgrade === 'undefined' || + req.headers.upgrade.toLowerCase() !== 'websocket') { + throw new Error('invalid headers'); + return; + } + + if (!req.headers['sec-websocket-key']) { + socket.end(); + throw new Error('websocket key is missing'); + } + + // calc key + var key = req.headers['sec-websocket-key']; + var shasum = crypto.createHash('sha1'); + shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + key = shasum.digest('base64'); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: websocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Accept: ' + key + ]; + + socket.write(headers.concat('', '').join('\r\n')); + socket.end(); +} + + +function return401(server, req, socket) { + var headers = [ + 'HTTP/1.1 401 Unauthorized' + , 'Content-type: text/html' + ]; + + socket.write(headers.concat('', '').join('\r\n')); + socket.end(); +} + +/** + * Server object, which will do the actual emitting + */ + +function Server(webServer) { + this.webServer = webServer; +} + +util.inherits(Server, events.EventEmitter); + +Server.prototype.close = function() { + this.webServer.close(); + if (this._socket) this._socket.end(); +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/README.md b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/README.md new file mode 100644 index 00000000..22aab8bd --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/README.md @@ -0,0 +1,53 @@ +# node-XMLHttpRequest # + +node-XMLHttpRequest is a wrapper for the built-in http client to emulate the +browser XMLHttpRequest object. + +This can be used with JS designed for browsers to improve reuse of code and +allow the use of existing libraries. + +Note: This library currently conforms to [XMLHttpRequest 1](http://www.w3.org/TR/XMLHttpRequest/). Version 2.0 will target [XMLHttpRequest Level 2](http://www.w3.org/TR/XMLHttpRequest2/). + +## Usage ## + +Here's how to include the module in your project and use as the browser-based +XHR object. + + var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; + var xhr = new XMLHttpRequest(); + +Note: use the lowercase string "xmlhttprequest" in your require(). On +case-sensitive systems (eg Linux) using uppercase letters won't work. + +## Versions ## + +Prior to 1.4.0 version numbers were arbitrary. From 1.4.0 on they conform to +the standard major.minor.bugfix. 1.x shouldn't necessarily be considered +stable just because it's above 0.x. + +Since the XMLHttpRequest API is stable this library's API is stable as +well. Major version numbers indicate significant core code changes. +Minor versions indicate minor core code changes or better conformity to +the W3C spec. + +## Supports ## + +* Async and synchronous requests +* GET, POST, PUT, and DELETE requests +* All spec methods (open, send, abort, getRequestHeader, + getAllRequestHeaders, event methods) +* Requests to all domains + +## Known Issues / Missing Features ## + +For a list of open issues or to report your own visit the [github issues +page](https://github.com/driverdan/node-XMLHttpRequest/issues). + +* Local file access may have unexpected results for non-UTF8 files +* Synchronous requests don't set headers properly +* Synchronous requests freeze node while waiting for response (But that's what you want, right? Stick with async!). +* Some events are missing, such as abort +* getRequestHeader is case-sensitive +* Cookies aren't persisted between requests +* Missing XML support +* Missing basic auth diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/autotest.watchr b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/autotest.watchr new file mode 100644 index 00000000..5324db6c --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/autotest.watchr @@ -0,0 +1,8 @@ +def run_all_tests + puts `clear` + puts `node tests/test-constants.js` + puts `node tests/test-headers.js` + puts `node tests/test-request.js` +end +watch('.*.js') { run_all_tests } +run_all_tests diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/example/demo.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/example/demo.js new file mode 100644 index 00000000..4f333de9 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/example/demo.js @@ -0,0 +1,16 @@ +var sys = require('util'); +var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; + +var xhr = new XMLHttpRequest(); + +xhr.onreadystatechange = function() { + sys.puts("State: " + this.readyState); + + if (this.readyState == 4) { + sys.puts("Complete.\nBody length: " + this.responseText.length); + sys.puts("Body:\n" + this.responseText); + } +}; + +xhr.open("GET", "http://driverdan.com"); +xhr.send(); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/lib/XMLHttpRequest.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/lib/XMLHttpRequest.js new file mode 100644 index 00000000..214a2e3b --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/lib/XMLHttpRequest.js @@ -0,0 +1,548 @@ +/** + * Wrapper for built-in http.js to emulate the browser XMLHttpRequest object. + * + * This can be used with JS designed for browsers to improve reuse of code and + * allow the use of existing libraries. + * + * Usage: include("XMLHttpRequest.js") and use XMLHttpRequest per W3C specs. + * + * @author Dan DeFelippi + * @contributor David Ellis + * @license MIT + */ + +var Url = require("url") + , spawn = require("child_process").spawn + , fs = require('fs'); + +exports.XMLHttpRequest = function() { + /** + * Private variables + */ + var self = this; + var http = require('http'); + var https = require('https'); + + // Holds http.js objects + var client; + var request; + var response; + + // Request settings + var settings = {}; + + // Set some default headers + var defaultHeaders = { + "User-Agent": "node-XMLHttpRequest", + "Accept": "*/*", + }; + + var headers = defaultHeaders; + + // These headers are not user setable. + // The following are allowed but banned in the spec: + // * user-agent + var forbiddenRequestHeaders = [ + "accept-charset", + "accept-encoding", + "access-control-request-headers", + "access-control-request-method", + "connection", + "content-length", + "content-transfer-encoding", + "cookie", + "cookie2", + "date", + "expect", + "host", + "keep-alive", + "origin", + "referer", + "te", + "trailer", + "transfer-encoding", + "upgrade", + "via" + ]; + + // These request methods are not allowed + var forbiddenRequestMethods = [ + "TRACE", + "TRACK", + "CONNECT" + ]; + + // Send flag + var sendFlag = false; + // Error flag, used when errors occur or abort is called + var errorFlag = false; + + // Event listeners + var listeners = {}; + + /** + * Constants + */ + + this.UNSENT = 0; + this.OPENED = 1; + this.HEADERS_RECEIVED = 2; + this.LOADING = 3; + this.DONE = 4; + + /** + * Public vars + */ + + // Current state + this.readyState = this.UNSENT; + + // default ready state change handler in case one is not set or is set late + this.onreadystatechange = null; + + // Result & response + this.responseText = ""; + this.responseXML = ""; + this.status = null; + this.statusText = null; + + /** + * Private methods + */ + + /** + * Check if the specified header is allowed. + * + * @param string header Header to validate + * @return boolean False if not allowed, otherwise true + */ + var isAllowedHttpHeader = function(header) { + return (header && forbiddenRequestHeaders.indexOf(header.toLowerCase()) === -1); + }; + + /** + * Check if the specified method is allowed. + * + * @param string method Request method to validate + * @return boolean False if not allowed, otherwise true + */ + var isAllowedHttpMethod = function(method) { + return (method && forbiddenRequestMethods.indexOf(method) === -1); + }; + + /** + * Public methods + */ + + /** + * Open the connection. Currently supports local server requests. + * + * @param string method Connection method (eg GET, POST) + * @param string url URL for the connection. + * @param boolean async Asynchronous connection. Default is true. + * @param string user Username for basic authentication (optional) + * @param string password Password for basic authentication (optional) + */ + this.open = function(method, url, async, user, password) { + this.abort(); + errorFlag = false; + + // Check for valid request method + if (!isAllowedHttpMethod(method)) { + throw "SecurityError: Request method not allowed"; + return; + } + + settings = { + "method": method, + "url": url.toString(), + "async": (typeof async !== "boolean" ? true : async), + "user": user || null, + "password": password || null + }; + + setState(this.OPENED); + }; + + /** + * Sets a header for the request. + * + * @param string header Header name + * @param string value Header value + */ + this.setRequestHeader = function(header, value) { + if (this.readyState != this.OPENED) { + throw "INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN"; + } + if (!isAllowedHttpHeader(header)) { + console.warn('Refused to set unsafe header "' + header + '"'); + return; + } + if (sendFlag) { + throw "INVALID_STATE_ERR: send flag is true"; + } + headers[header] = value; + }; + + /** + * Gets a header from the server response. + * + * @param string header Name of header to get. + * @return string Text of the header or null if it doesn't exist. + */ + this.getResponseHeader = function(header) { + if (typeof header === "string" + && this.readyState > this.OPENED + && response.headers[header.toLowerCase()] + && !errorFlag + ) { + return response.headers[header.toLowerCase()]; + } + + return null; + }; + + /** + * Gets all the response headers. + * + * @return string A string with all response headers separated by CR+LF + */ + this.getAllResponseHeaders = function() { + if (this.readyState < this.HEADERS_RECEIVED || errorFlag) { + return ""; + } + var result = ""; + + for (var i in response.headers) { + // Cookie headers are excluded + if (i !== "set-cookie" && i !== "set-cookie2") { + result += i + ": " + response.headers[i] + "\r\n"; + } + } + return result.substr(0, result.length - 2); + }; + + /** + * Gets a request header + * + * @param string name Name of header to get + * @return string Returns the request header or empty string if not set + */ + this.getRequestHeader = function(name) { + // @TODO Make this case insensitive + if (typeof name === "string" && headers[name]) { + return headers[name]; + } + + return ""; + } + + /** + * Sends the request to the server. + * + * @param string data Optional data to send as request body. + */ + this.send = function(data) { + if (this.readyState != this.OPENED) { + throw "INVALID_STATE_ERR: connection must be opened before send() is called"; + } + + if (sendFlag) { + throw "INVALID_STATE_ERR: send has already been called"; + } + + var ssl = false, local = false; + var url = Url.parse(settings.url); + + // Determine the server + switch (url.protocol) { + case 'https:': + ssl = true; + // SSL & non-SSL both need host, no break here. + case 'http:': + var host = url.hostname; + break; + + case 'file:': + local = true; + break; + + case undefined: + case '': + var host = "localhost"; + break; + + default: + throw "Protocol not supported."; + } + + // Load files off the local filesystem (file://) + if (local) { + if (settings.method !== "GET") { + throw "XMLHttpRequest: Only GET method is supported"; + } + + if (settings.async) { + fs.readFile(url.pathname, 'utf8', function(error, data) { + if (error) { + self.handleError(error); + } else { + self.status = 200; + self.responseText = data; + setState(self.DONE); + } + }); + } else { + try { + this.responseText = fs.readFileSync(url.pathname, 'utf8'); + this.status = 200; + setState(self.DONE); + } catch(e) { + this.handleError(e); + } + } + + return; + } + + // Default to port 80. If accessing localhost on another port be sure + // to use http://localhost:port/path + var port = url.port || (ssl ? 443 : 80); + // Add query string if one is used + var uri = url.pathname + (url.search ? url.search : ''); + + // Set the Host header or the server may reject the request + headers["Host"] = host; + if (!((ssl && port === 443) || port === 80)) { + headers["Host"] += ':' + url.port; + } + + // Set Basic Auth if necessary + if (settings.user) { + if (typeof settings.password == "undefined") { + settings.password = ""; + } + var authBuf = new Buffer(settings.user + ":" + settings.password); + headers["Authorization"] = "Basic " + authBuf.toString("base64"); + } + + // Set content length header + if (settings.method === "GET" || settings.method === "HEAD") { + data = null; + } else if (data) { + headers["Content-Length"] = Buffer.byteLength(data); + + if (!headers["Content-Type"]) { + headers["Content-Type"] = "text/plain;charset=UTF-8"; + } + } else if (settings.method === "POST") { + // For a post with no data set Content-Length: 0. + // This is required by buggy servers that don't meet the specs. + headers["Content-Length"] = 0; + } + + var options = { + host: host, + port: port, + path: uri, + method: settings.method, + headers: headers + }; + + // Reset error flag + errorFlag = false; + + // Handle async requests + if (settings.async) { + // Use the proper protocol + var doRequest = ssl ? https.request : http.request; + + // Request is being sent, set send flag + sendFlag = true; + + // As per spec, this is called here for historical reasons. + self.dispatchEvent("readystatechange"); + + // Create the request + request = doRequest(options, function(resp) { + response = resp; + response.setEncoding("utf8"); + + setState(self.HEADERS_RECEIVED); + self.status = response.statusCode; + + response.on('data', function(chunk) { + // Make sure there's some data + if (chunk) { + self.responseText += chunk; + } + // Don't emit state changes if the connection has been aborted. + if (sendFlag) { + setState(self.LOADING); + } + }); + + response.on('end', function() { + if (sendFlag) { + // Discard the 'end' event if the connection has been aborted + setState(self.DONE); + sendFlag = false; + } + }); + + response.on('error', function(error) { + self.handleError(error); + }); + }).on('error', function(error) { + self.handleError(error); + }); + + // Node 0.4 and later won't accept empty data. Make sure it's needed. + if (data) { + request.write(data); + } + + request.end(); + + self.dispatchEvent("loadstart"); + } else { // Synchronous + // Create a temporary file for communication with the other Node process + var syncFile = ".node-xmlhttprequest-sync-" + process.pid; + fs.writeFileSync(syncFile, "", "utf8"); + // The async request the other Node process executes + var execString = "var http = require('http'), https = require('https'), fs = require('fs');" + + "var doRequest = http" + (ssl ? "s" : "") + ".request;" + + "var options = " + JSON.stringify(options) + ";" + + "var responseText = '';" + + "var req = doRequest(options, function(response) {" + + "response.setEncoding('utf8');" + + "response.on('data', function(chunk) {" + + "responseText += chunk;" + + "});" + + "response.on('end', function() {" + + "fs.writeFileSync('" + syncFile + "', 'NODE-XMLHTTPREQUEST-STATUS:' + response.statusCode + ',' + responseText, 'utf8');" + + "});" + + "response.on('error', function(error) {" + + "fs.writeFileSync('" + syncFile + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');" + + "});" + + "}).on('error', function(error) {" + + "fs.writeFileSync('" + syncFile + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');" + + "});" + + (data ? "req.write('" + data.replace(/'/g, "\\'") + "');":"") + + "req.end();"; + // Start the other Node Process, executing this string + syncProc = spawn(process.argv[0], ["-e", execString]); + while((self.responseText = fs.readFileSync(syncFile, 'utf8')) == "") { + // Wait while the file is empty + } + // Kill the child process once the file has data + syncProc.stdin.end(); + // Remove the temporary file + fs.unlinkSync(syncFile); + if (self.responseText.match(/^NODE-XMLHTTPREQUEST-ERROR:/)) { + // If the file returned an error, handle it + var errorObj = self.responseText.replace(/^NODE-XMLHTTPREQUEST-ERROR:/, ""); + self.handleError(errorObj); + } else { + // If the file returned okay, parse its data and move to the DONE state + self.status = self.responseText.replace(/^NODE-XMLHTTPREQUEST-STATUS:([0-9]*),.*/, "$1"); + self.responseText = self.responseText.replace(/^NODE-XMLHTTPREQUEST-STATUS:[0-9]*,(.*)/, "$1"); + setState(self.DONE); + } + } + }; + + /** + * Called when an error is encountered to deal with it. + */ + this.handleError = function(error) { + this.status = 503; + this.statusText = error; + this.responseText = error.stack; + errorFlag = true; + setState(this.DONE); + }; + + /** + * Aborts a request. + */ + this.abort = function() { + if (request) { + request.abort(); + request = null; + } + + headers = defaultHeaders; + this.responseText = ""; + this.responseXML = ""; + + errorFlag = true; + + if (this.readyState !== this.UNSENT + && (this.readyState !== this.OPENED || sendFlag) + && this.readyState !== this.DONE) { + sendFlag = false; + setState(this.DONE); + } + this.readyState = this.UNSENT; + }; + + /** + * Adds an event listener. Preferred method of binding to events. + */ + this.addEventListener = function(event, callback) { + if (!(event in listeners)) { + listeners[event] = []; + } + // Currently allows duplicate callbacks. Should it? + listeners[event].push(callback); + }; + + /** + * Remove an event callback that has already been bound. + * Only works on the matching funciton, cannot be a copy. + */ + this.removeEventListener = function(event, callback) { + if (event in listeners) { + // Filter will return a new array with the callback removed + listeners[event] = listeners[event].filter(function(ev) { + return ev !== callback; + }); + } + }; + + /** + * Dispatch any events, including both "on" methods and events attached using addEventListener. + */ + this.dispatchEvent = function(event) { + if (typeof self["on" + event] === "function") { + self["on" + event](); + } + if (event in listeners) { + for (var i = 0, len = listeners[event].length; i < len; i++) { + listeners[event][i].call(self); + } + } + }; + + /** + * Changes readyState and calls onreadystatechange. + * + * @param int state New state + */ + var setState = function(state) { + if (self.readyState !== state) { + self.readyState = state; + + if (settings.async || self.readyState < self.OPENED || self.readyState === self.DONE) { + self.dispatchEvent("readystatechange"); + } + + if (self.readyState === self.DONE && !errorFlag) { + self.dispatchEvent("load"); + // @TODO figure out InspectorInstrumentation::didLoadXHR(cookie) + self.dispatchEvent("loadend"); + } + } + }; +}; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/package.json new file mode 100644 index 00000000..e1f4bf34 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/package.json @@ -0,0 +1,39 @@ +{ + "name": "xmlhttprequest", + "description": "XMLHttpRequest for Node", + "version": "1.4.2", + "author": { + "name": "Dan DeFelippi", + "url": "http://driverdan.com" + }, + "keywords": [ + "xhr", + "ajax" + ], + "licenses": [ + { + "type": "MIT", + "url": "http://creativecommons.org/licenses/MIT/" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/driverdan/node-XMLHttpRequest.git" + }, + "bugs": { + "url": "http://github.com/driverdan/node-XMLHttpRequest/issues" + }, + "engines": { + "node": ">=0.4.0" + }, + "directories": { + "lib": "./lib", + "example": "./example" + }, + "main": "./lib/XMLHttpRequest.js", + "readme": "# node-XMLHttpRequest #\n\nnode-XMLHttpRequest is a wrapper for the built-in http client to emulate the\nbrowser XMLHttpRequest object.\n\nThis can be used with JS designed for browsers to improve reuse of code and\nallow the use of existing libraries.\n\nNote: This library currently conforms to [XMLHttpRequest 1](http://www.w3.org/TR/XMLHttpRequest/). Version 2.0 will target [XMLHttpRequest Level 2](http://www.w3.org/TR/XMLHttpRequest2/).\n\n## Usage ##\n\nHere's how to include the module in your project and use as the browser-based\nXHR object.\n\n\tvar XMLHttpRequest = require(\"xmlhttprequest\").XMLHttpRequest;\n\tvar xhr = new XMLHttpRequest();\n\nNote: use the lowercase string \"xmlhttprequest\" in your require(). On\ncase-sensitive systems (eg Linux) using uppercase letters won't work.\n\n## Versions ##\n\nPrior to 1.4.0 version numbers were arbitrary. From 1.4.0 on they conform to\nthe standard major.minor.bugfix. 1.x shouldn't necessarily be considered\nstable just because it's above 0.x.\n\nSince the XMLHttpRequest API is stable this library's API is stable as\nwell. Major version numbers indicate significant core code changes.\nMinor versions indicate minor core code changes or better conformity to\nthe W3C spec.\n\n## Supports ##\n\n* Async and synchronous requests\n* GET, POST, PUT, and DELETE requests\n* All spec methods (open, send, abort, getRequestHeader,\n getAllRequestHeaders, event methods)\n* Requests to all domains\n\n## Known Issues / Missing Features ##\n\nFor a list of open issues or to report your own visit the [github issues\npage](https://github.com/driverdan/node-XMLHttpRequest/issues).\n\n* Local file access may have unexpected results for non-UTF8 files\n* Synchronous requests don't set headers properly\n* Synchronous requests freeze node while waiting for response (But that's what you want, right? Stick with async!).\n* Some events are missing, such as abort\n* getRequestHeader is case-sensitive\n* Cookies aren't persisted between requests\n* Missing XML support\n* Missing basic auth\n", + "readmeFilename": "README.md", + "homepage": "https://github.com/driverdan/node-XMLHttpRequest", + "_id": "xmlhttprequest@1.4.2", + "_from": "xmlhttprequest@1.4.2" +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-constants.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-constants.js new file mode 100644 index 00000000..372e46cc --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-constants.js @@ -0,0 +1,13 @@ +var sys = require("util") + , assert = require("assert") + , XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest + , xhr = new XMLHttpRequest(); + +// Test constant values +assert.equal(0, xhr.UNSENT); +assert.equal(1, xhr.OPENED); +assert.equal(2, xhr.HEADERS_RECEIVED); +assert.equal(3, xhr.LOADING); +assert.equal(4, xhr.DONE); + +sys.puts("done"); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-events.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-events.js new file mode 100644 index 00000000..c72f001d --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-events.js @@ -0,0 +1,50 @@ +var sys = require("util") + , assert = require("assert") + , http = require("http") + , XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest + , xhr; + +// Test server +var server = http.createServer(function (req, res) { + var body = (req.method != "HEAD" ? "Hello World" : ""); + + res.writeHead(200, { + "Content-Type": "text/plain", + "Content-Length": Buffer.byteLength(body) + }); + // HEAD has no body + if (req.method != "HEAD") { + res.write(body); + } + res.end(); + assert.equal(onreadystatechange, true); + assert.equal(readystatechange, true); + assert.equal(removed, true); + sys.puts("done"); + this.close(); +}).listen(8000); + +xhr = new XMLHttpRequest(); + +// Track event calls +var onreadystatechange = false; +var readystatechange = false; +var removed = true; +var removedEvent = function() { + removed = false; +}; + +xhr.onreadystatechange = function() { + onreadystatechange = true; +}; + +xhr.addEventListener("readystatechange", function() { + readystatechange = true; +}); + +// This isn't perfect, won't guarantee it was added in the first place +xhr.addEventListener("readystatechange", removedEvent); +xhr.removeEventListener("readystatechange", removedEvent); + +xhr.open("GET", "http://localhost:8000"); +xhr.send(); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-exceptions.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-exceptions.js new file mode 100644 index 00000000..f1edd71f --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-exceptions.js @@ -0,0 +1,62 @@ +var sys = require("util") + , assert = require("assert") + , XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest + , xhr = new XMLHttpRequest(); + +// Test request methods that aren't allowed +try { + xhr.open("TRACK", "http://localhost:8000/"); + console.log("ERROR: TRACK should have thrown exception"); +} catch(e) {} +try { + xhr.open("TRACE", "http://localhost:8000/"); + console.log("ERROR: TRACE should have thrown exception"); +} catch(e) {} +try { + xhr.open("CONNECT", "http://localhost:8000/"); + console.log("ERROR: CONNECT should have thrown exception"); +} catch(e) {} +// Test valid request method +try { + xhr.open("GET", "http://localhost:8000/"); +} catch(e) { + console.log("ERROR: Invalid exception for GET", e); +} + +// Test forbidden headers +var forbiddenRequestHeaders = [ + "accept-charset", + "accept-encoding", + "access-control-request-headers", + "access-control-request-method", + "connection", + "content-length", + "content-transfer-encoding", + "cookie", + "cookie2", + "date", + "expect", + "host", + "keep-alive", + "origin", + "referer", + "te", + "trailer", + "transfer-encoding", + "upgrade", + "user-agent", + "via" +]; + +for (var i in forbiddenRequestHeaders) { + try { + xhr.setRequestHeader(forbiddenRequestHeaders[i], "Test"); + console.log("ERROR: " + forbiddenRequestHeaders[i] + " should have thrown exception"); + } catch(e) { + } +} + +// Try valid header +xhr.setRequestHeader("X-Foobar", "Test"); + +console.log("Done"); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-headers.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-headers.js new file mode 100644 index 00000000..2ecb045d --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-headers.js @@ -0,0 +1,61 @@ +var sys = require("util") + , assert = require("assert") + , XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest + , xhr = new XMLHttpRequest() + , http = require("http"); + +// Test server +var server = http.createServer(function (req, res) { + // Test setRequestHeader + assert.equal("Foobar", req.headers["x-test"]); + + var body = "Hello World"; + res.writeHead(200, { + "Content-Type": "text/plain", + "Content-Length": Buffer.byteLength(body), + // Set cookie headers to see if they're correctly suppressed + // Actual values don't matter + "Set-Cookie": "foo=bar", + "Set-Cookie2": "bar=baz", + "Connection": "close" + }); + res.write("Hello World"); + res.end(); + + this.close(); +}).listen(8000); + +xhr.onreadystatechange = function() { + if (this.readyState == 4) { + // Test getAllResponseHeaders() + var headers = "content-type: text/plain\r\ncontent-length: 11\r\nconnection: close"; + assert.equal(headers, this.getAllResponseHeaders()); + + // Test case insensitivity + assert.equal('text/plain', this.getResponseHeader('Content-Type')); + assert.equal('text/plain', this.getResponseHeader('Content-type')); + assert.equal('text/plain', this.getResponseHeader('content-Type')); + assert.equal('text/plain', this.getResponseHeader('content-type')); + + // Test aborted getAllResponseHeaders + this.abort(); + assert.equal("", this.getAllResponseHeaders()); + assert.equal(null, this.getResponseHeader("Connection")); + + sys.puts("done"); + } +}; + +assert.equal(null, xhr.getResponseHeader("Content-Type")); +try { + xhr.open("GET", "http://localhost:8000/"); + // Valid header + xhr.setRequestHeader("X-Test", "Foobar"); + // Invalid header + xhr.setRequestHeader("Content-Length", 0); + // Test getRequestHeader + assert.equal("Foobar", xhr.getRequestHeader("X-Test")); + xhr.send(); +} catch(e) { + console.log("ERROR: Exception raised", e); +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-request-methods.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-request-methods.js new file mode 100644 index 00000000..fa1b1bed --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-request-methods.js @@ -0,0 +1,62 @@ +var sys = require("util") + , assert = require("assert") + , XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest + , http = require("http") + , xhr; + +// Test server +var server = http.createServer(function (req, res) { + // Check request method and URL + assert.equal(methods[curMethod], req.method); + assert.equal("/" + methods[curMethod], req.url); + + var body = (req.method != "HEAD" ? "Hello World" : ""); + + res.writeHead(200, { + "Content-Type": "text/plain", + "Content-Length": Buffer.byteLength(body) + }); + // HEAD has no body + if (req.method != "HEAD") { + res.write(body); + } + res.end(); + + if (curMethod == methods.length - 1) { + this.close(); + sys.puts("done"); + } +}).listen(8000); + +// Test standard methods +var methods = ["GET", "POST", "HEAD", "PUT", "DELETE"]; +var curMethod = 0; + +function start(method) { + // Reset each time + xhr = new XMLHttpRequest(); + + xhr.onreadystatechange = function() { + if (this.readyState == 4) { + if (method == "HEAD") { + assert.equal("", this.responseText); + } else { + assert.equal("Hello World", this.responseText); + } + + curMethod++; + + if (curMethod < methods.length) { + sys.puts("Testing " + methods[curMethod]); + start(methods[curMethod]); + } + } + }; + + var url = "http://localhost:8000/" + method; + xhr.open(method, url); + xhr.send(); +} + +sys.puts("Testing " + methods[curMethod]); +start(methods[curMethod]); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-request-protocols.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-request-protocols.js new file mode 100644 index 00000000..cd4e1745 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-request-protocols.js @@ -0,0 +1,34 @@ +var sys = require("util") + , assert = require("assert") + , XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest + , xhr; + +xhr = new XMLHttpRequest(); + +xhr.onreadystatechange = function() { + if (this.readyState == 4) { + assert.equal("Hello World", this.responseText); + this.close(); + runSync(); + } +}; + +// Async +var url = "file://" + __dirname + "/testdata.txt"; +xhr.open("GET", url); +xhr.send(); + +// Sync +var runSync = function() { + xhr = new XMLHttpRequest(); + + xhr.onreadystatechange = function() { + if (this.readyState == 4) { + assert.equal("Hello World", this.responseText); + this.close(); + sys.puts("done"); + } + }; + xhr.open("GET", url, false); + xhr.send(); +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/testdata.txt b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/testdata.txt new file mode 100644 index 00000000..557db03d --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/testdata.txt @@ -0,0 +1 @@ +Hello World diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/package.json b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/package.json new file mode 100644 index 00000000..569ad0b8 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/package.json @@ -0,0 +1,67 @@ +{ + "name": "socket.io-client", + "description": "Socket.IO client for the browser and node.js", + "version": "0.9.16", + "main": "./lib/io.js", + "browserify": "./dist/socket.io.js", + "homepage": "http://socket.io", + "keywords": [ + "websocket", + "socket", + "realtime", + "socket.io", + "comet", + "ajax" + ], + "author": { + "name": "Guillermo Rauch", + "email": "guillermo@learnboost.com" + }, + "contributors": [ + { + "name": "Guillermo Rauch", + "email": "rauchg@gmail.com" + }, + { + "name": "Arnout Kazemier", + "email": "info@3rd-eden.com" + }, + { + "name": "Vladimir Dronnikov", + "email": "dronnikov@gmail.com" + }, + { + "name": "Einar Otto Stangvik", + "email": "einaros@gmail.com" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/LearnBoost/socket.io-client.git" + }, + "dependencies": { + "uglify-js": "1.2.5", + "ws": "0.4.x", + "xmlhttprequest": "1.4.2", + "active-x-obfuscator": "0.0.1" + }, + "devDependencies": { + "expresso": "*", + "express": "2.5.x", + "jade": "*", + "stylus": "*", + "socket.io": "0.9.16", + "socket.io-client": "0.9.16", + "should": "*" + }, + "engines": { + "node": ">= 0.4.0" + }, + "readme": "socket.io\n=========\n\n#### Sockets for the rest of us\n\nThe `socket.io` client is basically a simple HTTP Socket interface implementation.\nIt looks similar to WebSocket while providing additional features and\nleveraging other transports when WebSocket is not supported by the user's\nbrowser.\n\n```js\nvar socket = io.connect('http://domain.com');\nsocket.on('connect', function () {\n // socket connected\n});\nsocket.on('custom event', function () {\n // server emitted a custom event\n});\nsocket.on('disconnect', function () {\n // socket disconnected\n});\nsocket.send('hi there');\n```\n\n### Recipes\n\n#### Utilizing namespaces (ie: multiple sockets)\n\nIf you want to namespace all the messages and events emitted to a particular\nendpoint, simply specify it as part of the `connect` uri:\n\n```js\nvar chat = io.connect('http://localhost/chat');\nchat.on('connect', function () {\n // chat socket connected\n});\n\nvar news = io.connect('/news'); // io.connect auto-detects host\nnews.on('connect', function () {\n // news socket connected\n});\n```\n\n#### Emitting custom events\n\nTo ease with the creation of applications, you can emit custom events outside\nof the global `message` event.\n\n```js\nvar socket = io.connect();\nsocket.emit('server custom event', { my: 'data' });\n```\n\n#### Forcing disconnection\n\n```js\nvar socket = io.connect();\nsocket.on('connect', function () {\n socket.disconnect();\n});\n```\n\n### Documentation \n\n#### io#connect\n\n```js\nio.connect(uri, [options]);\n```\n\n##### Options:\n\n- *resource*\n\n socket.io\n\n The resource is what allows the `socket.io` server to identify incoming connections by `socket.io` clients. In other words, any HTTP server can implement socket.io and still serve other normal, non-realtime HTTP requests.\n\n- *transports*\n\n```js\n['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling']\n```\n\n A list of the transports to attempt to utilize (in order of preference).\n\n- *'connect timeout'*\n\n```js\n5000\n```\n\n The amount of milliseconds a transport has to create a connection before we consider it timed out.\n \n- *'try multiple transports'*\n\n```js\ntrue\n```\n\n A boolean indicating if we should try other transports when the connectTimeout occurs.\n \n- *reconnect*\n\n```js\ntrue\n```\n\n A boolean indicating if we should automatically reconnect if a connection is disconnected. \n \n- *'reconnection delay'*\n\n```js\n500\n```\n\n The amount of milliseconds before we try to connect to the server again. We are using a exponential back off algorithm for the following reconnections, on each reconnect attempt this value will get multiplied (500 > 1000 > 2000 > 4000 > 8000).\n \n\n- *'max reconnection attempts'*\n\n```js\n10\n```\n\n The amount of attempts should we make using the current transport to connect to the server? After this we will do one final attempt, and re-try with all enabled transport methods before we give up.\n\n##### Properties:\n\n- *options*\n\n The passed in options combined with the defaults.\n\n- *connected*\n\n Whether the socket is connected or not.\n \n- *connecting*\n\n Whether the socket is connecting or not.\n\n- *reconnecting*\n\n Whether we are reconnecting or not.\n \n- *transport* \n\n The transport instance.\n\n##### Methods:\n \n- *connect(λ)*\n\n Establishes a connection. If λ is supplied as argument, it will be called once the connection is established.\n \n- *send(message)*\n \n A string of data to send.\n \n- *disconnect*\n\n Closes the connection.\n \n- *on(event, λ)*\n\n Adds a listener for the event *event*.\n\n- *once(event, λ)*\n\n Adds a one time listener for the event *event*. The listener is removed after the first time the event is fired.\n \n- *removeListener(event, λ)*\n\n Removes the listener λ for the event *event*.\n \n##### Events:\n\n- *connect*\n\n Fired when the connection is established and the handshake successful.\n \n- *connecting(transport_type)*\n\n Fired when a connection is attempted, passing the transport name.\n \n- *connect_failed*\n\n Fired when the connection timeout occurs after the last connection attempt.\n This only fires if the `connectTimeout` option is set.\n If the `tryTransportsOnConnectTimeout` option is set, this only fires once all\n possible transports have been tried.\n \n- *message(message)*\n \n Fired when a message arrives from the server\n\n- *close*\n\n Fired when the connection is closed. Be careful with using this event, as some transports will fire it even under temporary, expected disconnections (such as XHR-Polling).\n \n- *disconnect*\n\n Fired when the connection is considered disconnected.\n \n- *reconnect(transport_type,reconnectionAttempts)*\n\n Fired when the connection has been re-established. This only fires if the `reconnect` option is set.\n\n- *reconnecting(reconnectionDelay,reconnectionAttempts)*\n\n Fired when a reconnection is attempted, passing the next delay for the next reconnection.\n\n- *reconnect_failed*\n\n Fired when all reconnection attempts have failed and we where unsuccessful in reconnecting to the server. \n\n### Contributors\n\nGuillermo Rauch <guillermo@learnboost.com>\n\nArnout Kazemier <info@3rd-eden.com>\n\n### License \n\n(The MIT License)\n\nCopyright (c) 2010 LearnBoost <dev@learnboost.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/LearnBoost/socket.io-client/issues" + }, + "_id": "socket.io-client@0.9.16", + "_from": "socket.io-client@0.9.16" +} diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/events.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/events.test.js new file mode 100644 index 00000000..365c4223 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/events.test.js @@ -0,0 +1,120 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (module, io, should) { + + module.exports = { + + 'add listeners': function () { + var event = new io.EventEmitter + , calls = 0; + + event.on('test', function (a, b) { + ++calls; + a.should().eql('a'); + b.should().eql('b'); + }); + + event.emit('test', 'a', 'b'); + calls.should().eql(1); + event.on.should().eql(event.addListener); + }, + + 'remove listener': function () { + var event = new io.EventEmitter; + function empty () { } + + event.on('test', empty); + event.on('test:more', empty); + event.removeAllListeners('test'); + + event.listeners('test').should().eql([]); + event.listeners('test:more').should().eql([empty]); + }, + + 'remove all listeners with no arguments': function () { + var event = new io.EventEmitter; + function empty () { } + + event.on('test', empty); + event.on('test:more', empty); + event.removeAllListeners(); + + event.listeners('test').should().eql([]); + event.listeners('test:more').should().eql([]); + }, + + 'remove listeners functions': function () { + var event = new io.EventEmitter + , calls = 0; + + function one () { ++calls } + function two () { ++calls } + function three () { ++calls } + + event.on('one', one); + event.removeListener('one', one); + event.listeners('one').should().eql([]); + + event.on('two', two); + event.removeListener('two', one); + event.listeners('two').should().eql([two]); + + event.on('three', three); + event.on('three', two); + event.removeListener('three', three); + event.listeners('three').should().eql([two]); + }, + + 'number of arguments': function () { + var event = new io.EventEmitter + , number = []; + + event.on('test', function () { + number.push(arguments.length); + }); + + event.emit('test'); + event.emit('test', null); + event.emit('test', null, null); + event.emit('test', null, null, null); + event.emit('test', null, null, null, null); + event.emit('test', null, null, null, null, null); + + [0, 1, 2, 3, 4, 5].should().eql(number); + }, + + 'once': function () { + var event = new io.EventEmitter + , calls = 0; + + event.once('test', function (a, b) { + ++calls; + }); + + event.emit('test', 'a', 'b'); + event.emit('test', 'a', 'b'); + event.emit('test', 'a', 'b'); + + function removed () { + should().fail('not removed'); + }; + + event.once('test:removed', removed); + event.removeListener('test:removed', removed); + event.emit('test:removed'); + + calls.should().eql(1); + } + + }; + +})( + 'undefined' == typeof module ? module = {} : module + , 'undefined' == typeof io ? require('socket.io-client') : io + , 'undefined' == typeof should || !should.fail ? require('should') : should +); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/io.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/io.test.js new file mode 100644 index 00000000..d9f0b09e --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/io.test.js @@ -0,0 +1,31 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (module, io, should) { + + module.exports = { + + 'client version number': function () { + io.version.should().match(/([0-9]+)\.([0-9]+)\.([0-9]+)/); + }, + + 'socket.io protocol version': function () { + io.protocol.should().be.a('number'); + io.protocol.toString().should().match(/^\d+$/); + }, + + 'socket.io available transports': function () { + (io.transports.length > 0).should().be_true; + } + + }; + +})( + 'undefined' == typeof module ? module = {} : module + , 'undefined' == typeof io ? require('socket.io-client') : io + , 'undefined' == typeof should ? require('should') : should +); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/node/builder.common.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/node/builder.common.js new file mode 100644 index 00000000..fa8d46ed --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/node/builder.common.js @@ -0,0 +1,102 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +var vm = require('vm') + , should = require('should'); + +/** + * Generates evn variables for the vm so we can `emulate` a browser. + * @returns {Object} evn variables + */ + +exports.env = function env () { + var details = { + location: { + port: 8080 + , host: 'www.example.org' + , hostname: 'www.example.org' + , href: 'http://www.example.org/example/' + , pathname: '/example/' + , protocol: 'http:' + , search: '' + , hash: '' + } + , console: { + log: function(){}, + info: function(){}, + warn: function(){}, + error: function(){} + } + , navigator: { + userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit' + + '/534.27 (KHTML, like Gecko) Chrome/12.0.716.0 Safari/534.27' + , appName: 'socket.io' + , platform: process.platform + , appVersion: process.version + , } + , name: 'socket.io' + , innerWidth: 1024 + , innerHeight: 768 + , length: 1 + , outerWidth: 1024 + , outerHeight: 768 + , pageXOffset: 0 + , pageYOffset: 0 + , screenX: 0 + , screenY: 0 + , screenLeft: 0 + , screenTop: 0 + , scrollX: 0 + , scrollY: 0 + , scrollTop: 0 + , scrollLeft: 0 + , screen: { + width: 0 + , height: 0 + } + }; + + // circular references + details.window = details.self = details.contentWindow = details; + + // callable methods + details.Image = details.scrollTo = details.scrollBy = details.scroll = + details.resizeTo = details.resizeBy = details.prompt = details.print = + details.open = details.moveTo = details.moveBy = details.focus = + details.createPopup = details.confirm = details.close = details.blur = + details.alert = details.clearTimeout = details.clearInterval = + details.setInterval = details.setTimeout = details.XMLHttpRequest = + details.getComputedStyle = details.trigger = details.dispatchEvent = + details.removeEventListener = details.addEventListener = function(){}; + + // frames + details.frames = [details]; + + // document + details.document = details; + details.document.domain = details.location.href; + + return details; +}; + +/** + * Executes a script in a browser like env and returns + * the result + * + * @param {String} contents The script content + * @returns {Object} The evaluated script. + */ + +exports.execute = function execute (contents) { + var env = exports.env() + , script = vm.createScript(contents); + + // run the script with `browser like` globals + script.runInNewContext(env); + + return env; +}; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/node/builder.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/node/builder.test.js new file mode 100644 index 00000000..989e2bc5 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/node/builder.test.js @@ -0,0 +1,131 @@ +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +var builder = require('../../bin/builder') + , common = require('./builder.common') + , should = require('should'); + +/** + * Tests. + */ + +module.exports = { + + 'version number': function () { + builder.version.should().match(/([0-9]+)\.([0-9]+)\.([0-9]+)/); + builder.version.should().equal(require('../../lib/io').version); + }, + + 'production build LOC': function () { + builder(function (err, result) { + should.strictEqual(err, null) + + var lines = result.split('\n'); + lines.length.should().be.below(5); + lines[0].should().match(/production/gi); + Buffer.byteLength(result).should().be.below(43000); + }); + }, + + 'development build LOC': function () { + builder({ minify: false }, function (err, result) { + should.strictEqual(err, null) + + var lines = result.split('\n'); + lines.length.should().be.above(5); + lines[0].should().match(/development/gi); + Buffer.byteLength(result).should().be.above(35000); + }); + }, + + 'default builds': function () { + builder(function (err, result) { + should.strictEqual(err, null); + + var io = common.execute(result).io + , transports = Object.keys(io.Transport) + , defaults = Object.keys(builder.transports); + + /* XHR transport is private, but still available */ + transports.length.should().be.equal(defaults.length + 1); + + defaults.forEach(function (transport) { + transports.indexOf(transport).should().be.above(-1); + }) + }); + }, + + 'custom build': function () { + builder(['websocket'], function (err, result) { + should.strictEqual(err, null); + + var io = common.execute(result).io + , transports = Object.keys(io.Transport); + + transports.should().have.length(1); + transports[0].should().eql('websocket'); + }); + }, + + 'custom code': function () { + var custom = 'var hello = "world";'; + builder({ custom: [custom], minify: false }, function (err, result) { + should.strictEqual(err, null); + + result.should().include.string(custom); + }); + }, + + 'node if': function () { + var custom = '// if node \nvar hello = "world";\n' + + '// end node\nvar pew = "pew";'; + + builder({ custom: [custom], minify: false }, function (err, result) { + should.strictEqual(err, null); + + result.should().not.include.string(custom); + result.should().not.include.string('// if node'); + result.should().not.include.string('// end node'); + result.should().not.include.string('"world"'); + + result.should().include.string('var pew = "pew"'); + }); + }, + + 'preserve the encoding during minification': function () { + builder(function (err, result) { + should.strictEqual(err, null); + + result.should().match(/(\\ufffd)/g); + }) + }, + + 'globals': function () { + builder(function (err, result) { + should.strictEqual(err, null); + + var io = common.execute(result) + , env = common.env() + , allowed = ['io', 'swfobject', 'WEB_SOCKET_DISABLE_AUTO_INITIALIZATION']; + + Array.prototype.push.apply(allowed, Object.keys(env)); + + Object.keys(io).forEach(function (global) { + var index = allowed.indexOf(global); + + // the global is not allowed! + if (!~index) { + throw new Error('Global leak: ' + global); + } + }); + }) + } + +}; diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/parser.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/parser.test.js new file mode 100644 index 00000000..0022afb2 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/parser.test.js @@ -0,0 +1,360 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (module, io, should) { + + var parser = io.parser; + + module.exports = { + + 'decoding error packet': function () { + parser.decodePacket('7:::').should().eql({ + type: 'error' + , reason: '' + , advice: '' + , endpoint: '' + }); + }, + + 'decoding error packet with reason': function () { + parser.decodePacket('7:::0').should().eql({ + type: 'error' + , reason: 'transport not supported' + , advice: '' + , endpoint: '' + }); + }, + + 'decoding error packet with reason and advice': function () { + parser.decodePacket('7:::2+0').should().eql({ + type: 'error' + , reason: 'unauthorized' + , advice: 'reconnect' + , endpoint: '' + }); + }, + + 'decoding error packet with endpoint': function () { + parser.decodePacket('7::/woot').should().eql({ + type: 'error' + , reason: '' + , advice: '' + , endpoint: '/woot' + }); + }, + + 'decoding ack packet': function () { + parser.decodePacket('6:::140').should().eql({ + type: 'ack' + , ackId: '140' + , endpoint: '' + , args: [] + }); + }, + + 'decoding ack packet with args': function () { + parser.decodePacket('6:::12+["woot","wa"]').should().eql({ + type: 'ack' + , ackId: '12' + , endpoint: '' + , args: ['woot', 'wa'] + }); + }, + + 'decoding ack packet with bad json': function () { + var thrown = false; + + try { + parser.decodePacket('6:::1+{"++]').should().eql({ + type: 'ack' + , ackId: '1' + , endpoint: '' + , args: [] + }); + } catch (e) { + thrown = true; + } + + thrown.should().be_false; + }, + + 'decoding json packet': function () { + parser.decodePacket('4:::"2"').should().eql({ + type: 'json' + , endpoint: '' + , data: '2' + }); + }, + + 'decoding json packet with message id and ack data': function () { + parser.decodePacket('4:1+::{"a":"b"}').should().eql({ + type: 'json' + , id: 1 + , ack: 'data' + , endpoint: '' + , data: { a: 'b' } + }); + }, + + 'decoding an event packet': function () { + parser.decodePacket('5:::{"name":"woot"}').should().eql({ + type: 'event' + , name: 'woot' + , endpoint: '' + , args: [] + }); + }, + + 'decoding an event packet with message id and ack': function () { + parser.decodePacket('5:1+::{"name":"tobi"}').should().eql({ + type: 'event' + , id: 1 + , ack: 'data' + , endpoint: '' + , name: 'tobi' + , args: [] + }); + }, + + 'decoding an event packet with data': function () { + parser.decodePacket('5:::{"name":"edwald","args":[{"a": "b"},2,"3"]}') + .should().eql({ + type: 'event' + , name: 'edwald' + , endpoint: '' + , args: [{a: 'b'}, 2, '3'] + }); + }, + + 'decoding a message packet': function () { + parser.decodePacket('3:::woot').should().eql({ + type: 'message' + , endpoint: '' + , data: 'woot' + }); + }, + + 'decoding a message packet with id and endpoint': function () { + parser.decodePacket('3:5:/tobi').should().eql({ + type: 'message' + , id: 5 + , ack: true + , endpoint: '/tobi' + , data: '' + }); + }, + + 'decoding a heartbeat packet': function () { + parser.decodePacket('2:::').should().eql({ + type: 'heartbeat' + , endpoint: '' + }); + }, + + 'decoding a connection packet': function () { + parser.decodePacket('1::/tobi').should().eql({ + type: 'connect' + , endpoint: '/tobi' + , qs: '' + }); + }, + + 'decoding a connection packet with query string': function () { + parser.decodePacket('1::/test:?test=1').should().eql({ + type: 'connect' + , endpoint: '/test' + , qs: '?test=1' + }); + }, + + 'decoding a disconnection packet': function () { + parser.decodePacket('0::/woot').should().eql({ + type: 'disconnect' + , endpoint: '/woot' + }); + }, + + 'encoding error packet': function () { + parser.encodePacket({ + type: 'error' + , reason: '' + , advice: '' + , endpoint: '' + }).should().eql('7::'); + }, + + 'encoding error packet with reason': function () { + parser.encodePacket({ + type: 'error' + , reason: 'transport not supported' + , advice: '' + , endpoint: '' + }).should().eql('7:::0'); + }, + + 'encoding error packet with reason and advice': function () { + parser.encodePacket({ + type: 'error' + , reason: 'unauthorized' + , advice: 'reconnect' + , endpoint: '' + }).should().eql('7:::2+0'); + }, + + 'encoding error packet with endpoint': function () { + parser.encodePacket({ + type: 'error' + , reason: '' + , advice: '' + , endpoint: '/woot' + }).should().eql('7::/woot'); + }, + + 'encoding ack packet': function () { + parser.encodePacket({ + type: 'ack' + , ackId: '140' + , endpoint: '' + , args: [] + }).should().eql('6:::140'); + }, + + 'encoding ack packet with args': function () { + parser.encodePacket({ + type: 'ack' + , ackId: '12' + , endpoint: '' + , args: ['woot', 'wa'] + }).should().eql('6:::12+["woot","wa"]'); + }, + + 'encoding json packet': function () { + parser.encodePacket({ + type: 'json' + , endpoint: '' + , data: '2' + }).should().eql('4:::"2"'); + }, + + 'encoding json packet with message id and ack data': function () { + parser.encodePacket({ + type: 'json' + , id: 1 + , ack: 'data' + , endpoint: '' + , data: { a: 'b' } + }).should().eql('4:1+::{"a":"b"}'); + }, + + 'encoding an event packet': function () { + parser.encodePacket({ + type: 'event' + , name: 'woot' + , endpoint: '' + , args: [] + }).should().eql('5:::{"name":"woot"}'); + }, + + 'encoding an event packet with message id and ack': function () { + parser.encodePacket({ + type: 'event' + , id: 1 + , ack: 'data' + , endpoint: '' + , name: 'tobi' + , args: [] + }).should().eql('5:1+::{"name":"tobi"}'); + }, + + 'encoding an event packet with data': function () { + parser.encodePacket({ + type: 'event' + , name: 'edwald' + , endpoint: '' + , args: [{a: 'b'}, 2, '3'] + }).should().eql('5:::{"name":"edwald","args":[{"a":"b"},2,"3"]}'); + }, + + 'encoding a message packet': function () { + parser.encodePacket({ + type: 'message' + , endpoint: '' + , data: 'woot' + }).should().eql('3:::woot'); + }, + + 'encoding a message packet with id and endpoint': function () { + parser.encodePacket({ + type: 'message' + , id: 5 + , ack: true + , endpoint: '/tobi' + , data: '' + }).should().eql('3:5:/tobi'); + }, + + 'encoding a heartbeat packet': function () { + parser.encodePacket({ + type: 'heartbeat' + , endpoint: '' + }).should().eql('2::'); + }, + + 'encoding a connection packet': function () { + parser.encodePacket({ + type: 'connect' + , endpoint: '/tobi' + , qs: '' + }).should().eql('1::/tobi'); + }, + + 'encoding a connection packet with query string': function () { + parser.encodePacket({ + type: 'connect' + , endpoint: '/test' + , qs: '?test=1' + }).should().eql('1::/test:?test=1'); + }, + + 'encoding a disconnection packet': function () { + parser.encodePacket({ + type: 'disconnect' + , endpoint: '/woot' + }).should().eql('0::/woot'); + }, + + 'test decoding a payload': function () { + parser.decodePayload('\ufffd5\ufffd3:::5\ufffd7\ufffd3:::53d' + + '\ufffd3\ufffd0::').should().eql([ + { type: 'message', data: '5', endpoint: '' } + , { type: 'message', data: '53d', endpoint: '' } + , { type: 'disconnect', endpoint: '' } + ]); + }, + + 'test encoding a payload': function () { + parser.encodePayload([ + parser.encodePacket({ type: 'message', data: '5', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: '53d', endpoint: '' }) + ]).should().eql('\ufffd5\ufffd3:::5\ufffd7\ufffd3:::53d') + }, + + 'test decoding newline': function () { + parser.decodePacket('3:::\n').should().eql({ + type: 'message' + , endpoint: '' + , data: '\n' + }); + } + + }; + +})( + 'undefined' == typeof module ? module = {} : module + , 'undefined' == typeof io ? require('socket.io-client') : io + , 'undefined' == typeof should ? require('should') : should +); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/socket.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/socket.test.js new file mode 100644 index 00000000..eae49564 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/socket.test.js @@ -0,0 +1,422 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (module, io, should) { + + if ('object' == typeof global) { + return module.exports = { '': function () {} }; + } + + module.exports = { + + 'test connecting the socket and disconnecting': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('connect', function () { + socket.disconnect(); + next(); + }); + }, + + 'test receiving messages': function (next) { + var socket = create() + , connected = false + , messages = 0; + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('connect', function () { + connected = true; + }); + + socket.on('message', function (i) { + String(++messages).should().equal(i); + }); + + socket.on('disconnect', function (reason) { + connected.should().be_true; + messages.should().equal(3); + reason.should().eql('booted'); + next(); + }); + }, + + 'test sending messages': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('connect', function () { + socket.send('echo'); + + socket.on('message', function (msg) { + msg.should().equal('echo'); + socket.disconnect(); + next(); + }); + }); + }, + + 'test manual buffer flushing': function (next) { + var socket = create(); + + socket.socket.options['manualFlush'] = true; + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('connect', function () { + socket.socket.connected = false; + socket.send('buffered'); + socket.socket.onConnect(); + socket.socket.flushBuffer(); + + socket.on('message', function (msg) { + msg.should().equal('buffered'); + socket.disconnect(); + next(); + }); + }); + }, + + 'test automatic buffer flushing': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('connect', function () { + socket.socket.connected = false; + socket.send('buffered'); + socket.socket.onConnect(); + + socket.on('message', function (msg) { + msg.should().equal('buffered'); + socket.disconnect(); + next(); + }); + }); + }, + + 'test acks sent from client': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('connect', function () { + socket.on('message', function (msg) { + if ('tobi 2' == msg) { + socket.disconnect(); + next(); + } + }); + }); + }, + + 'test acks sent from server': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('connect', function () { + socket.send('ooo', function () { + socket.disconnect(); + next(); + }); + }); + }, + + 'test connecting to namespaces': function (next) { + var io = create() + , socket = io.socket + , namespaces = 2 + , connect = 0; + + function finish () { + socket.of('').disconnect(); + connect.should().equal(3); + next(); + } + + socket.on('connect', function(){ + connect++; + }); + + socket.of('/woot').on('connect', function () { + connect++; + }).on('message', function (msg) { + msg.should().equal('connected to woot'); + --namespaces || finish(); + }).on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.of('/chat').on('connect', function () { + connect++; + }).on('message', function (msg) { + msg.should().equal('connected to chat'); + --namespaces || finish(); + }).on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + }, + + 'test disconnecting from namespaces': function (next) { + var socket = create().socket + , namespaces = 2 + , disconnections = 0; + + function finish () { + socket.of('').disconnect(); + next(); + }; + + socket.of('/a').on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.of('/a').on('connect', function () { + socket.of('/a').disconnect(); + }); + + socket.of('/a').on('disconnect', function () { + --namespaces || finish(); + }); + + socket.of('/b').on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.of('/b').on('connect', function () { + socket.of('/b').disconnect(); + }); + + socket.of('/b').on('disconnect', function () { + --namespaces || finish(); + }); + }, + + 'test authorizing for namespaces': function (next) { + var socket = create().socket + + function finish () { + socket.of('').disconnect(); + next(); + }; + + socket.of('/a') + .on('connect_failed', function (msg) { + next(); + }) + .on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + }, + + 'test sending json from server': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('message', function (msg) { + msg.should().eql(3141592); + socket.disconnect(); + next(); + }); + }, + + 'test sending json from client': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.json.send([1, 2, 3]); + socket.on('message', function (msg) { + msg.should().equal('echo'); + socket.disconnect(); + next(); + }); + }, + + 'test emitting an event from server': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('woot', function () { + socket.disconnect(); + next(); + }); + }, + + 'test emitting an event to server': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.emit('woot'); + socket.on('echo', function () { + socket.disconnect(); + next(); + }) + }, + + 'test emitting multiple events at once to the server': function (next) { + var socket = create(); + + socket.on('connect', function () { + socket.emit('print', 'foo'); + socket.emit('print', 'bar'); + }); + + socket.on('done', function () { + socket.disconnect(); + next(); + }); + }, + + 'test emitting an event from server and sending back data': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('woot', function (a, fn) { + a.should().eql(1); + fn('test'); + + socket.on('done', function () { + socket.disconnect(); + next(); + }); + }); + }, + + 'test emitting an event to server and sending back data': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.emit('tobi', 1, 2, function (a) { + a.should().eql({ hello: 'world' }); + socket.disconnect(); + next(); + }); + }, + + 'test encoding a payload': function (next) { + var socket = create('/woot'); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('connect', function () { + socket.socket.setBuffer(true); + socket.send('ñ'); + socket.send('ñ'); + socket.send('ñ'); + socket.send('ñ'); + socket.socket.setBuffer(false); + }); + + socket.on('done', function () { + socket.disconnect(); + next(); + }); + }, + + 'test sending query strings to the server': function (next) { + var socket = create('?foo=bar'); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.on('message', function (data) { + data.query.foo.should().eql('bar'); + + socket.disconnect(); + next(); + }); + }, + + 'test sending newline': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.send('\n'); + + socket.on('done', function () { + socket.disconnect(); + next(); + }); + }, + + 'test sending unicode': function (next) { + var socket = create(); + + socket.on('error', function (msg) { + throw new Error(msg || 'Received an error'); + }); + + socket.json.send({ test: "☃" }); + + socket.on('done', function () { + socket.disconnect(); + next(); + }); + }, + + 'test webworker connection': function (next) { + if (!window.Worker) { + return next(); + } + + var worker = new Worker('/test/worker.js'); + worker.postMessage(uri()); + worker.onmessage = function (ev) { + if ('done!' == ev.data) return next(); + throw new Error('Unexpected message: ' + ev.data); + } + } + + }; + +})( + 'undefined' == typeof module ? module = {} : module + , 'undefined' == typeof io ? require('socket.io-client') : io + , 'undefined' == typeof should ? require('should-browser') : should +); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/util.test.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/util.test.js new file mode 100644 index 00000000..30db5a63 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/util.test.js @@ -0,0 +1,156 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (module, io, should) { + + module.exports = { + + 'parse uri': function () { + var http = io.util.parseUri('http://google.com') + , https = io.util.parseUri('https://www.google.com:80') + , query = io.util.parseUri('google.com:8080/foo/bar?foo=bar'); + + http.protocol.should().eql('http'); + http.port.should().eql(''); + http.host.should().eql('google.com'); + https.protocol.should().eql('https'); + https.port.should().eql('80'); + https.host.should().eql('www.google.com'); + query.port.should().eql('8080'); + query.query.should().eql('foo=bar'); + query.path.should().eql('/foo/bar'); + query.relative.should().eql('/foo/bar?foo=bar'); + }, + + 'unique uri': function () { + var protocol = io.util.parseUri('http://google.com') + , noprotocol = io.util.parseUri('google.com') + , https = io.util.parseUri('https://google.com') + , path = io.util.parseUri('https://google.com/google.com/com/?foo=bar'); + + if ('object' == typeof window) { + io.util.uniqueUri(protocol).should().eql('http://google.com:3000'); + io.util.uniqueUri(noprotocol).should().eql('http://google.com:3000'); + } else { + io.util.uniqueUri(protocol).should().eql('http://google.com:80'); + io.util.uniqueUri(noprotocol).should().eql('http://google.com:80'); + } + + io.util.uniqueUri(https).should().eql('https://google.com:443'); + io.util.uniqueUri(path).should().eql('https://google.com:443'); + }, + + 'chunk query string': function () { + io.util.chunkQuery('foo=bar').should().be.a('object'); + io.util.chunkQuery('foo=bar').foo.should().eql('bar'); + }, + + 'merge query strings': function () { + var base = io.util.query('foo=bar', 'foo=baz') + , add = io.util.query('foo=bar', 'bar=foo') + + base.should().eql('?foo=baz'); + add.should().eql('?foo=bar&bar=foo'); + + io.util.query('','').should().eql(''); + io.util.query('foo=bar', '').should().eql('?foo=bar'); + io.util.query('', 'foo=bar').should().eql('?foo=bar'); + }, + + 'request': function () { + var type = typeof io.util.request(); + type.should().eql('object'); + }, + + 'is array': function () { + io.util.isArray([]).should().be_true; + io.util.isArray({}).should().be_false; + io.util.isArray('str').should().be_false; + io.util.isArray(new Date).should().be_false; + io.util.isArray(true).should().be_false; + io.util.isArray(arguments).should().be_false; + }, + + 'merge, deep merge': function () { + var start = { + foo: 'bar' + , bar: 'baz' + } + , duplicate = { + foo: 'foo' + , bar: 'bar' + } + , extra = { + ping: 'pong' + } + , deep = { + level1:{ + foo: 'bar' + , level2: { + foo: 'bar' + , level3:{ + foo: 'bar' + , rescursive: deep + } + } + } + } + // same structure, but changed names + , deeper = { + foo: 'bar' + , level1:{ + foo: 'baz' + , level2: { + foo: 'foo' + , level3:{ + foo: 'pewpew' + , rescursive: deep + } + } + } + }; + + io.util.merge(start, duplicate); + + start.foo.should().eql('foo'); + start.bar.should().eql('bar'); + + io.util.merge(start, extra); + start.ping.should().eql('pong'); + start.foo.should().eql('foo'); + + io.util.merge(deep, deeper); + + deep.foo.should().eql('bar'); + deep.level1.foo.should().eql('baz'); + deep.level1.level2.foo.should().eql('foo'); + deep.level1.level2.level3.foo.should().eql('pewpew'); + }, + + 'defer': function (next) { + var now = +new Date; + + io.util.defer(function () { + ((new Date - now) >= ( io.util.webkit ? 100 : 0 )).should().be_true(); + next(); + }) + }, + + 'indexOf': function () { + var data = ['socket', 2, 3, 4, 'socket', 5, 6, 7, 'io']; + io.util.indexOf(data, 'socket', 1).should().eql(4); + io.util.indexOf(data, 'socket').should().eql(0); + io.util.indexOf(data, 'waffles').should().eql(-1); + } + + }; + +})( + 'undefined' == typeof module ? module = {} : module + , 'undefined' == typeof io ? require('socket.io-client') : io + , 'undefined' == typeof should ? require('should') : should +); diff --git a/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/worker.js b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/worker.js new file mode 100644 index 00000000..c5426326 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/test/worker.js @@ -0,0 +1,20 @@ +importScripts('/socket.io/socket.io.js'); + +self.onmessage = function (ev) { + var url = ev.data + , socket = io.connect(url); + + socket.on('done', function () { + self.postMessage('done!'); + }); + + socket.on('connect_failed', function () { + self.postMessage('connect failed'); + }); + + socket.on('error', function () { + self.postMessage('error'); + }); + + socket.send('woot'); +} diff --git a/node_modules/karma/node_modules/socket.io/package.json b/node_modules/karma/node_modules/socket.io/package.json new file mode 100644 index 00000000..17428b02 --- /dev/null +++ b/node_modules/karma/node_modules/socket.io/package.json @@ -0,0 +1,70 @@ +{ + "name": "socket.io", + "version": "0.9.16", + "description": "Real-time apps made cross-browser & easy with a WebSocket-like API", + "homepage": "http://socket.io", + "keywords": [ + "websocket", + "socket", + "realtime", + "socket.io", + "comet", + "ajax" + ], + "author": { + "name": "Guillermo Rauch", + "email": "guillermo@learnboost.com" + }, + "contributors": [ + { + "name": "Guillermo Rauch", + "email": "rauchg@gmail.com" + }, + { + "name": "Arnout Kazemier", + "email": "info@3rd-eden.com" + }, + { + "name": "Vladimir Dronnikov", + "email": "dronnikov@gmail.com" + }, + { + "name": "Einar Otto Stangvik", + "email": "einaros@gmail.com" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/LearnBoost/socket.io.git" + }, + "dependencies": { + "socket.io-client": "0.9.16", + "policyfile": "0.0.4", + "base64id": "0.1.0", + "redis": "0.7.3" + }, + "devDependencies": { + "expresso": "0.9.2", + "should": "*", + "benchmark": "0.2.2", + "microtime": "0.1.3-1", + "colors": "0.5.1" + }, + "optionalDependencies": { + "redis": "0.7.3" + }, + "main": "index", + "engines": { + "node": ">= 0.4.0" + }, + "scripts": { + "test": "make test" + }, + "readme": "# Socket.IO\n\nSocket.IO is a Node.JS project that makes WebSockets and realtime possible in\nall browsers. It also enhances WebSockets by providing built-in multiplexing,\nhorizontal scalability, automatic JSON encoding/decoding, and more.\n\n## How to Install\n\n```bash\nnpm install socket.io\n```\n\n## How to use\n\nFirst, require `socket.io`:\n\n```js\nvar io = require('socket.io');\n```\n\nNext, attach it to a HTTP/HTTPS server. If you're using the fantastic `express`\nweb framework:\n\n#### Express 3.x\n\n```js\nvar app = express()\n , server = require('http').createServer(app)\n , io = io.listen(server);\n\nserver.listen(80);\n\nio.sockets.on('connection', function (socket) {\n socket.emit('news', { hello: 'world' });\n socket.on('my other event', function (data) {\n console.log(data);\n });\n});\n```\n\n#### Express 2.x\n\n```js\nvar app = express.createServer()\n , io = io.listen(app);\n\napp.listen(80);\n\nio.sockets.on('connection', function (socket) {\n socket.emit('news', { hello: 'world' });\n socket.on('my other event', function (data) {\n console.log(data);\n });\n});\n```\n\nFinally, load it from the client side code:\n\n```html\n\n\n```\n\nFor more thorough examples, look at the `examples/` directory.\n\n## Short recipes\n\n### Sending and receiving events.\n\nSocket.IO allows you to emit and receive custom events.\nBesides `connect`, `message` and `disconnect`, you can emit custom events:\n\n```js\n// note, io.listen() will create a http server for you\nvar io = require('socket.io').listen(80);\n\nio.sockets.on('connection', function (socket) {\n io.sockets.emit('this', { will: 'be received by everyone' });\n\n socket.on('private message', function (from, msg) {\n console.log('I received a private message by ', from, ' saying ', msg);\n });\n\n socket.on('disconnect', function () {\n io.sockets.emit('user disconnected');\n });\n});\n```\n\n### Storing data associated to a client\n\nSometimes it's necessary to store data associated with a client that's\nnecessary for the duration of the session.\n\n#### Server side\n\n```js\nvar io = require('socket.io').listen(80);\n\nio.sockets.on('connection', function (socket) {\n socket.on('set nickname', function (name) {\n socket.set('nickname', name, function () { socket.emit('ready'); });\n });\n\n socket.on('msg', function () {\n socket.get('nickname', function (err, name) {\n console.log('Chat message by ', name);\n });\n });\n});\n```\n\n#### Client side\n\n```html\n\n```\n\n### Restricting yourself to a namespace\n\nIf you have control over all the messages and events emitted for a particular\napplication, using the default `/` namespace works.\n\nIf you want to leverage 3rd-party code, or produce code to share with others,\nsocket.io provides a way of namespacing a `socket`.\n\nThis has the benefit of `multiplexing` a single connection. Instead of\nsocket.io using two `WebSocket` connections, it'll use one.\n\nThe following example defines a socket that listens on '/chat' and one for\n'/news':\n\n#### Server side\n\n```js\nvar io = require('socket.io').listen(80);\n\nvar chat = io\n .of('/chat')\n .on('connection', function (socket) {\n socket.emit('a message', { that: 'only', '/chat': 'will get' });\n chat.emit('a message', { everyone: 'in', '/chat': 'will get' });\n });\n\nvar news = io\n .of('/news');\n .on('connection', function (socket) {\n socket.emit('item', { news: 'item' });\n });\n```\n\n#### Client side:\n\n```html\n\n```\n\n### Sending volatile messages.\n\nSometimes certain messages can be dropped. Let's say you have an app that\nshows realtime tweets for the keyword `bieber`. \n\nIf a certain client is not ready to receive messages (because of network slowness\nor other issues, or because he's connected through long polling and is in the\nmiddle of a request-response cycle), if he doesn't receive ALL the tweets related\nto bieber your application won't suffer.\n\nIn that case, you might want to send those messages as volatile messages.\n\n#### Server side\n\n```js\nvar io = require('socket.io').listen(80);\n\nio.sockets.on('connection', function (socket) {\n var tweets = setInterval(function () {\n getBieberTweet(function (tweet) {\n socket.volatile.emit('bieber tweet', tweet);\n });\n }, 100);\n\n socket.on('disconnect', function () {\n clearInterval(tweets);\n });\n});\n```\n\n#### Client side\n\nIn the client side, messages are received the same way whether they're volatile\nor not.\n\n### Getting acknowledgements\n\nSometimes, you might want to get a callback when the client confirmed the message\nreception.\n\nTo do this, simply pass a function as the last parameter of `.send` or `.emit`.\nWhat's more, when you use `.emit`, the acknowledgement is done by you, which\nmeans you can also pass data along:\n\n#### Server side\n\n```js\nvar io = require('socket.io').listen(80);\n\nio.sockets.on('connection', function (socket) {\n socket.on('ferret', function (name, fn) {\n fn('woot');\n });\n});\n```\n\n#### Client side\n\n```html\n\n```\n\n### Broadcasting messages\n\nTo broadcast, simply add a `broadcast` flag to `emit` and `send` method calls.\nBroadcasting means sending a message to everyone else except for the socket\nthat starts it.\n\n#### Server side\n\n```js\nvar io = require('socket.io').listen(80);\n\nio.sockets.on('connection', function (socket) {\n socket.broadcast.emit('user connected');\n socket.broadcast.json.send({ a: 'message' });\n});\n```\n\n### Rooms\n\nSometimes you want to put certain sockets in the same room, so that it's easy\nto broadcast to all of them together.\n\nThink of this as built-in channels for sockets. Sockets `join` and `leave`\nrooms in each socket.\n\n#### Server side\n\n```js\nvar io = require('socket.io').listen(80);\n\nio.sockets.on('connection', function (socket) {\n socket.join('justin bieber fans');\n socket.broadcast.to('justin bieber fans').emit('new fan');\n io.sockets.in('rammstein fans').emit('new non-fan');\n});\n```\n\n### Using it just as a cross-browser WebSocket\n\nIf you just want the WebSocket semantics, you can do that too.\nSimply leverage `send` and listen on the `message` event:\n\n#### Server side\n\n```js\nvar io = require('socket.io').listen(80);\n\nio.sockets.on('connection', function (socket) {\n socket.on('message', function () { });\n socket.on('disconnect', function () { });\n});\n```\n\n#### Client side\n\n```html\n\n```\n\n### Changing configuration\n\nConfiguration in socket.io is TJ-style:\n\n#### Server side\n\n```js\nvar io = require('socket.io').listen(80);\n\nio.configure(function () {\n io.set('transports', ['websocket', 'flashsocket', 'xhr-polling']);\n});\n\nio.configure('development', function () {\n io.set('transports', ['websocket', 'xhr-polling']);\n io.enable('log');\n});\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 Guillermo Rauch <guillermo@learnboost.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/LearnBoost/socket.io/issues" + }, + "_id": "socket.io@0.9.16", + "_from": "socket.io@~0.9.13" +} diff --git a/node_modules/karma/node_modules/useragent/.npmignore b/node_modules/karma/node_modules/useragent/.npmignore new file mode 100644 index 00000000..ad02c133 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/.npmignore @@ -0,0 +1,3 @@ +tests +benchmark +node_modules diff --git a/node_modules/karma/node_modules/useragent/.travis.yml b/node_modules/karma/node_modules/useragent/.travis.yml new file mode 100644 index 00000000..6875969f --- /dev/null +++ b/node_modules/karma/node_modules/useragent/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.7 + - 0.8 diff --git a/node_modules/karma/node_modules/useragent/CHANGELOG.md b/node_modules/karma/node_modules/useragent/CHANGELOG.md new file mode 100644 index 00000000..9262b3c7 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/CHANGELOG.md @@ -0,0 +1,63 @@ +## Version 2.0 +* __v2.0.0__ *breaking* + - Added support for Operating System version parsing + - Added support for Device parsing + - Introduced deferred OnDemand parsing for Operating and Devices + - The `Agent#toJSON` method now returns an object instread of JSON string. Use + `JSON.stringify(agent)` instead. + - Removed the fromAgent method + - semver is removed from the dependencies, if you use the useragent/features + you should add it to your own dependencies. + +* __v2.0.1__ + - Fixed broken reference to the update module. + - Updated with some new parsers. + +* __v2.0.2__ + - Use LRU-cache for the lookups so it doesn't create a memory "leak" #22 + - Updated with some new parsers. + +* __v2.0.3__ + - Updated regexp library with new parsers as Opera's latest browser which runs + WebKit was detected as Chrome Mobile. + +* __v2.0.4__ + - Added support for IE11 and PhantomJS. In addition to that when you run the + updater without the correct dependencies it will just output an error + instead of throwing an error. + +* __v2.0.5__ + - Upgraded the regular expressions to support Opera Next + +* __v2.0.6__ + - Only write the parse file when there isn't an error. #30 + - Output an error in the console when we fail to compile new parsers #30 + +## Version 1.0 +* __v1.1.0__ + - Removed the postupdate hook, it was causing to much issues #9 + +* __v1.0.6__ + - Updated the agent parser, JHint issues and leaking globals. + +* __v1.0.5__ + - Potential fix for #11 where it doesn't install the stuff in windows this also + brings a fresh update of the agents.js. + +* __v1.0.3__ + - Rewritten the `is` method so it doesn't display IE as true for firefox, chrome + etc fixes #10 and #7. + +* __v1.0.3__ + - A fix for bug #6, updated the semver dependency for browserify support. + +* __v1.0.2__ + - Don't throw errors when .parse is called without a useragent string. It now + defaults to a empty Agent instance. + +* __v1.0.1__ + - Added support for cURL, Wget and thunderbird using a custom useragent + definition file. + +* __v1.0.0__ *breaking* + - Complete rewrite of the API and major performance improvements. diff --git a/node_modules/karma/node_modules/useragent/CREDITS b/node_modules/karma/node_modules/useragent/CREDITS new file mode 100644 index 00000000..b5641547 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/CREDITS @@ -0,0 +1,16 @@ +The regex library that the useragent parser uses if from; code.google.com/p/ua-parser/ +which is released under Apache license: + +# Copyright 2009 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +#     http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/node_modules/karma/node_modules/useragent/LICENSE b/node_modules/karma/node_modules/useragent/LICENSE new file mode 100644 index 00000000..a4d6a95f --- /dev/null +++ b/node_modules/karma/node_modules/useragent/LICENSE @@ -0,0 +1,19 @@ +# MIT LICENSED Copyright (c) 2013 Arnout Kazemier (http://3rd-Eden.com) +# +# 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: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# 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. diff --git a/node_modules/karma/node_modules/useragent/README.md b/node_modules/karma/node_modules/useragent/README.md new file mode 100644 index 00000000..52ba4792 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/README.md @@ -0,0 +1,393 @@ +# useragent - high performance user agent parser for Node.js + +Useragent originated as port of [browserscope.org][browserscope]'s user agent +parser project also known as ua-parser. Useragent allows you to parse user agent +string with high accuracy by using hand tuned dedicated regular expressions for +browser matching. This database is needed to ensure that every browser is +correctly parsed as every browser vendor implements it's own user agent schema. +This is why regular user agent parsers have major issues because they will +most likely parse out the wrong browser name or confuse the render engine version +with the actual version of the browser. + +--- + +### Build status [![BuildStatus](https://secure.travis-ci.org/3rd-Eden/useragent.png?branch=master)](http://travis-ci.org/3rd-Eden/useragent) + +--- + +### High performance + +The module has been developed with a benchmark driven approach. It has a +pre-compiled library that contains all the Regular Expressions and uses deferred +or on demand parsing for Operating System and device information. All this +engineering effort has been worth it as [this benchmark shows][benchmark]: + +``` +Starting the benchmark, parsing 62 useragent strings per run + +Executed benchmark against node module: "useragent" +Count (61), Cycles (5), Elapsed (5.559), Hz (1141.3739447904327) + +Executed benchmark against node module: "useragent_parser" +Count (29), Cycles (3), Elapsed (5.448), Hz (545.6817291171243) + +Executed benchmark against node module: "useragent-parser" +Count (16), Cycles (4), Elapsed (5.48), Hz (304.5373431830105) + +Executed benchmark against node module: "ua-parser" +Count (54), Cycles (3), Elapsed (5.512), Hz (1018.7561434659247) + +Module: "useragent" is the user agent fastest parser. +``` + +--- + +### Installation + +Installation is done using the Node Package Manager (NPM). If you don't have +NPM installed on your system you can download it from +[npmjs.org][npm] + +``` +npm install useragent --save +``` + +The `--save` flag tells NPM to automatically add it to your `package.json` file. + +--- + +### API + + +Include the `useragent` parser in you node.js application: + +```js +var useragent = require('useragent'); +``` + +The `useragent` library allows you do use the automatically installed RegExp +library or you can fetch it live from the remote servers. So if you are +paranoid and always want your RegExp library to be up to date to match with +agent the widest range of `useragent` strings you can do: + +```js +var useragent = require('useragent'); +useragent(true); +``` + +This will async load the database from the server and compile it to a proper +JavaScript supported format. If it fails to compile or load it from the remote +location it will just fall back silently to the shipped version. If you want to +use this feature you need to add `yamlparser` and `request` to your package.json + +``` +npm install yamlparser --save +npm install request --save +``` + +#### useragent.parse(useragent string[, js useragent]); + +This is the actual user agent parser, this is where all the magic is happening. +The function accepts 2 arguments, both should be a `string`. The first argument +should the user agent string that is known on the server from the +`req.headers.useragent` header. The other argument is optional and should be +the user agent string that you see in the browser, this can be send from the +browser using a xhr request or something like this. This allows you detect if +the user is browsing the web using the `Chrome Frame` extension. + +The parser returns a Agent instance, this allows you to output user agent +information in different predefined formats. See the Agent section for more +information. + +```js +var agent = useragent.parse(req.headers['user-agent']); + +// example for parsing both the useragent header and a optional js useragent +var agent2 = useragent.parse(req.headers['user-agent'], req.query.jsuseragent); +``` + +The parse method returns a `Agent` instance which contains all details about the +user agent. See the Agent section of the API documentation for the available +methods. + +#### useragent.lookup(useragent string[, js useragent]); + +This provides the same functionality as above, but it caches the user agent +string and it's parsed result in memory to provide faster lookups in the +future. This can be handy if you expect to parse a lot of user agent strings. + +It uses the same arguments as the `useragent.parse` method and returns exactly +the same result, but it's just cached. + +```js +var agent = useragent.lookup(req.headers['user-agent']); +``` + +And this is a serious performance improvement as shown in this benchmark: + +``` +Executed benchmark against method: "useragent.parse" +Count (49), Cycles (3), Elapsed (5.534), Hz (947.6844321931629) + +Executed benchmark against method: "useragent.lookup" +Count (11758), Cycles (3), Elapsed (5.395), Hz (229352.03831239208) +``` + +#### useragent.fromJSON(obj); + +Transforms the JSON representation of a `Agent` instance back in to a working +`Agent` instance + +```js +var agent = useragent.parse(req.headers['user-agent']) + , another = useragent.fromJSON(JSON.stringify(agent)); + +console.log(agent == another); +``` + +#### useragent.is(useragent string).browsername; + +This api provides you with a quick and dirty browser lookup. The underlying +code is usually found on client side scripts so it's not the same quality as +our `useragent.parse` method but it might be needed for legacy reasons. + +`useragent.is` returns a object with potential matched browser names + +```js +useragent.is(req.headers['user-agent']).firefox // true +useragent.is(req.headers['user-agent']).safari // false +var ua = useragent.is(req.headers['user-agent']) + +// the object +{ + version: '3' + webkit: false + opera: false + ie: false + chrome: false + safari: false + mobile_safari: false + firefox: true +} +``` + +--- + +### Agents, OperatingSystem and Device instances + +Most of the methods mentioned above return a Agent instance. The Agent exposes +the parsed out information from the user agent strings. This allows us to +extend the agent with more methods that do not necessarily need to be in the +core agent instance, allowing us to expose a plugin interface for third party +developers and at the same time create a uniform interface for all versioning. + +The Agent has the following property + +- `family` The browser family, or browser name, it defaults to Other. +- `major` The major version number of the family, it defaults to 0. +- `minor` The minor version number of the family, it defaults to 0. +- `patch` The patch version number of the family, it defaults to 0. + +In addition to the properties mentioned above, it also has 2 special properties, +which are: + +- `os` OperatingSystem instance +- `device` Device instance + +When you access those 2 properties the agent will do on demand parsing of the +Operating System or/and Device information. + +The OperatingSystem has the same properties as the Agent, for the Device we +don't have any versioning information available, so only the `family` property is +set there. If we cannot find the family, they will default to `Other`. + +The following methods are available: + +#### Agent.toAgent(); + +Returns the family and version number concatinated in a nice human readable +string. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.toAgent(); // 'Chrome 15.0.874' +``` + +#### Agent.toString(); + +Returns the results of the `Agent.toAgent()` but also adds the parsed operating +system to the string in a human readable format. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.toString(); // 'Chrome 15.0.874 / Mac OS X 10.8.1' + +// as it's a to string method you can also concat it with another string +'your useragent is ' + agent; +// 'your useragent is Chrome 15.0.874 / Mac OS X 10.8.1' +``` +#### Agent.toVersion(); + +Returns the version of the browser in a human readable string. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.toVersion(); // '15.0.874' +``` + +#### Agent.toJSON(); + +Generates a JSON representation of the Agent. By using the `toJSON` method we +automatically allow it to be stringified when supplying as to the +`JSON.stringify` method. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.toJSON(); // returns an object + +JSON.stringify(agent); +``` + +#### OperatingSystem.toString(); + +Generates a stringified version of operating system; + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.os.toString(); // 'Mac OSX 10.8.1' +``` + +#### OperatingSystem.toVersion(); + +Generates a stringified version of operating system's version; + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.os.toVersion(); // '10.8.1' +``` + +#### OperatingSystem.toJSON(); + +Generates a JSON representation of the OperatingSystem. By using the `toJSON` +method we automatically allow it to be stringified when supplying as to the +`JSON.stringify` method. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.os.toJSON(); // returns an object + +JSON.stringify(agent.os); +``` + +#### Device.toString(); + +Generates a stringified version of device; + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.device.toString(); // 'Asus A100' +``` + +#### Device.toVersion(); + +Generates a stringified version of device's version; + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.device.toVersion(); // '' , no version found but could also be '0.0.0' +``` + +#### Device.toJSON(); + +Generates a JSON representation of the Device. By using the `toJSON` method we +automatically allow it to be stringified when supplying as to the +`JSON.stringify` method. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.device.toJSON(); // returns an object + +JSON.stringify(agent.device); +``` + +### Adding more features to the useragent + +As I wanted to keep the core of the user agent parser as clean and fast as +possible I decided to move some of the initially planned features to a new +`plugin` file. + +These extensions to the Agent prototype can be loaded by requiring the +`useragent/features` file: + +```js +var useragent = require('useragent'); +require('useragent/features'); +``` + +The initial release introduces 1 new method, satisfies, which allows you to see +if the version number of the browser satisfies a certain range. It uses the +semver library to do all the range calculations but here is a small summary of +the supported range styles: + +* `>1.2.3` Greater than a specific version. +* `<1.2.3` Less than. +* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`. +* `~1.2.3` := `>=1.2.3 <1.3.0`. +* `~1.2` := `>=1.2.0 <2.0.0`. +* `~1` := `>=1.0.0 <2.0.0`. +* `1.2.x` := `>=1.2.0 <1.3.0`. +* `1.x` := `>=1.0.0 <2.0.0`. + +As it requires the `semver` module to function you need to install it +seperately: + +``` +npm install semver --save +``` + +#### Agent.satisfies('range style here'); + +Check if the agent matches the supplied range. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.satisfies('15.x || >=19.5.0 || 25.0.0 - 17.2.3'); // true +agent.satisfies('>16.12.0'); // false +``` +--- + +### Migrations + +For small changes between version please review the [changelog][changelog]. + +#### Upgrading from 1.10 to 2.0.0 + +- `useragent.fromAgent` has been removed. +- `agent.toJSON` now returns an Object, use `JSON.stringify(agent)` for the old + behaviour. +- `agent.os` is now an `OperatingSystem` instance with version numbers. If you + still a string only representation do `agent.os.toString()`. +- `semver` has been removed from the dependencies, so if you are using the + `require('useragent/features')` you need to add it to your own dependencies + +#### Upgrading from 0.1.2 to 1.0.0 + +- `useragent.browser(ua)` has been renamed to `useragent.is(ua)`. +- `useragent.parser(ua, jsua)` has been renamed to `useragent.parse(ua, jsua)`. +- `result.pretty()` has been renamed to `result.toAgent()`. +- `result.V1` has been renamed to `result.major`. +- `result.V2` has been renamed to `result.minor`. +- `result.V3` has been renamed to `result.patch`. +- `result.prettyOS()` has been removed. +- `result.match` has been removed. + +--- + +### License + +MIT + +[browserscope]: http://www.browserscope.org/ +[benchmark]: /3rd-Eden/useragent/blob/master/benchmark/run.js +[changelog]: /3rd-Eden/useragent/blob/master/CHANGELOG.md +[npm]: http://npmjs.org diff --git a/node_modules/karma/node_modules/useragent/bin/testfiles.js b/node_modules/karma/node_modules/useragent/bin/testfiles.js new file mode 100755 index 00000000..f01a6d7a --- /dev/null +++ b/node_modules/karma/node_modules/useragent/bin/testfiles.js @@ -0,0 +1,24 @@ +#!/usr/bin/env node + +var request = require('request') + , path = require('path') + , fs = require('fs'); + +var files = { + 'pgts.yaml': 'https://raw.github.com/tobie/ua-parser/master/test_resources/pgts_browser_list.yaml' + , 'testcases.yaml': 'https://raw.github.com/tobie/ua-parser/master/test_resources/test_user_agent_parser.yaml' + , 'firefoxes.yaml': 'https://raw.github.com/tobie/ua-parser/master/test_resources/firefox_user_agent_strings.yaml' +}; + +/** + * Update the fixtures + */ + +Object.keys(files).forEach(function (key) { + request(files[key], function response (err, res, data) { + if (err || res.statusCode !== 200) return console.error('failed to update'); + + console.log('downloaded', files[key]); + fs.writeFileSync(path.join(__dirname, '..', 'tests', 'fixtures', key), data); + }); +}); diff --git a/node_modules/karma/node_modules/useragent/bin/update.js b/node_modules/karma/node_modules/useragent/bin/update.js new file mode 100755 index 00000000..28c25014 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/bin/update.js @@ -0,0 +1,17 @@ +#!/usr/bin/env node + +'use strict'; + +/** + * Update our definition file. + */ +require('../lib/update').update(function updating(err, data) { + if (err) { + console.error('Update unsuccessfull due to reasons'); + console.log(err.message); + console.log(err.stack); + + return; + } + console.log('Successfully fetched and generated new parsers from the internets.'); +}); diff --git a/node_modules/karma/node_modules/useragent/features/index.js b/node_modules/karma/node_modules/useragent/features/index.js new file mode 100644 index 00000000..5dab04aa --- /dev/null +++ b/node_modules/karma/node_modules/useragent/features/index.js @@ -0,0 +1,19 @@ +"use strict"; + +/** + * Plugin dependencies + */ +var Agent = require('../').Agent + , semver = require('semver'); + +/** + * Checks if the user agent's version can be satisfied agents the give + * ranged argument. This uses the semver libraries range construction. + * + * @param {String} ranged The range the version has to satisfie + * @returns {Boolean} + * @api public + */ +Agent.prototype.satisfies = function satisfies (range) { + return semver.satisfies(this.major + '.' + this.minor + '.' + this.patch, range); +}; diff --git a/node_modules/karma/node_modules/useragent/index.js b/node_modules/karma/node_modules/useragent/index.js new file mode 100644 index 00000000..f239a36e --- /dev/null +++ b/node_modules/karma/node_modules/useragent/index.js @@ -0,0 +1,598 @@ +'use strict'; + +/** + * This is where all the magic comes from, specially crafted for `useragent`. + */ +var regexps = require('./lib/regexps'); + +/** + * Reduce references by storing the lookups. + */ +// OperatingSystem parsers: +var osparsers = regexps.os + , osparserslength = osparsers.length; + +// UserAgent parsers: +var agentparsers = regexps.browser + , agentparserslength = agentparsers.length; + +// Device parsers: +var deviceparsers = regexps.device + , deviceparserslength = deviceparsers.length; + +/** + * The representation of a parsed user agent. + * + * @constructor + * @param {String} family The name of the browser + * @param {String} major Major version of the browser + * @param {String} minor Minor version of the browser + * @param {String} patch Patch version of the browser + * @param {String} source The actual user agent string + * @api public + */ +function Agent(family, major, minor, patch, source) { + this.family = family || 'Other'; + this.major = major || '0'; + this.minor = minor || '0'; + this.patch = patch || '0'; + this.source = source || ''; +} + +/** + * OnDemand parsing of the Operating System. + * + * @type {OperatingSystem} + * @api public + */ +Object.defineProperty(Agent.prototype, 'os', { + get: function lazyparse() { + var userAgent = this.source + , length = osparserslength + , parsers = osparsers + , i = 0 + , parser + , res; + + for (; i < length; i++) { + if (res = parsers[i][0].exec(userAgent)) { + parser = parsers[i]; + + if (parser[1]) res[1] = parser[1].replace('$1', res[1]); + break; + } + } + + return Object.defineProperty(this, 'os', { + value: !parser || !res + ? new OperatingSystem() + : new OperatingSystem( + res[1] + , parser[2] || res[2] + , parser[3] || res[3] + , parser[4] || res[4] + ) + }).os; + }, + + /** + * Bypass the OnDemand parsing and set an OperatingSystem instance. + * + * @param {OperatingSystem} os + * @api public + */ + set: function set(os) { + if (!(os instanceof OperatingSystem)) return false; + + return Object.defineProperty(this, 'os', { + value: os + }).os; + } +}); + +/** + * OnDemand parsing of the Device type. + * + * @type {Device} + * @api public + */ +Object.defineProperty(Agent.prototype, 'device', { + get: function lazyparse() { + var userAgent = this.source + , length = deviceparserslength + , parsers = deviceparsers + , i = 0 + , parser + , res; + + for (; i < length; i++) { + if (res = parsers[i][0].exec(userAgent)) { + parser = parsers[i]; + + if (parser[1]) res[1] = parser[1].replace('$1', res[1]); + break; + } + } + + return Object.defineProperty(this, 'device', { + value: !parser || !res + ? new Device() + : new Device( + res[1] + , parser[2] || res[2] + , parser[3] || res[3] + , parser[4] || res[4] + ) + }).device; + }, + + /** + * Bypass the OnDemand parsing and set an Device instance. + * + * @param {Device} device + * @api public + */ + set: function set(device) { + if (!(device instanceof Device)) return false; + + return Object.defineProperty(this, 'device', { + value: device + }).device; + } +}); +/*** Generates a string output of the parsed user agent. + * + * @returns {String} + * @api public + */ +Agent.prototype.toAgent = function toAgent() { + var output = this.family + , version = this.toVersion(); + + if (version) output += ' '+ version; + return output; +}; + +/** + * Generates a string output of the parser user agent and operating system. + * + * @returns {String} "UserAgent 0.0.0 / OS" + * @api public + */ +Agent.prototype.toString = function toString() { + var agent = this.toAgent() + , os = this.os !== 'Other' ? this.os : false; + + return agent + (os ? ' / ' + os : ''); +}; + +/** + * Outputs a compiled veersion number of the user agent. + * + * @returns {String} + * @api public + */ +Agent.prototype.toVersion = function toVersion() { + var version = ''; + + if (this.major) { + version += this.major; + + if (this.minor) { + version += '.' + this.minor; + + // Special case here, the patch can also be Alpha, Beta etc so we need + // to check if it's a string or not. + if (this.patch) { + version += (isNaN(+this.patch) ? ' ' : '.') + this.patch; + } + } + } + + return version; +}; + +/** + * Outputs a JSON string of the Agent. + * + * @returns {String} + * @api public + */ +Agent.prototype.toJSON = function toJSON() { + return { + family: this.family + , major: this.major + , minor: this.minor + , patch: this.patch + , device: this.device + , os: this.os + }; +}; + +/** + * The representation of a parsed Operating System. + * + * @constructor + * @param {String} family The name of the os + * @param {String} major Major version of the os + * @param {String} minor Minor version of the os + * @param {String} patch Patch version of the os + * @api public + */ +function OperatingSystem(family, major, minor, patch) { + this.family = family || 'Other'; + this.major = major || ''; + this.minor = minor || ''; + this.patch = patch || ''; +} + +/** + * Generates a stringified version of the Operating System. + * + * @returns {String} "Operating System 0.0.0" + * @api public + */ +OperatingSystem.prototype.toString = function toString() { + var output = this.family + , version = this.toVersion(); + + if (version) output += ' '+ version; + return output; +}; + +/** + * Generates the version of the Operating System. + * + * @returns {String} + * @api public + */ +OperatingSystem.prototype.toVersion = function toVersion() { + var version = ''; + + if (this.major) { + version += this.major; + + if (this.minor) { + version += '.' + this.minor; + + // Special case here, the patch can also be Alpha, Beta etc so we need + // to check if it's a string or not. + if (this.patch) { + version += (isNaN(+this.patch) ? ' ' : '.') + this.patch; + } + } + } + + return version; +}; + +/** + * Outputs a JSON string of the OS, values are defaulted to undefined so they + * are not outputed in the stringify. + * + * @returns {String} + * @api public + */ +OperatingSystem.prototype.toJSON = function toJSON(){ + return { + family: this.family + , major: this.major || undefined + , minor: this.minor || undefined + , patch: this.patch || undefined + }; +}; + +/** + * The representation of a parsed Device. + * + * @constructor + * @param {String} family The name of the os + * @api public + */ +function Device(family, major, minor, patch) { + this.family = family || 'Other'; + this.major = major || ''; + this.minor = minor || ''; + this.patch = patch || ''; +} + +/** + * Generates a stringified version of the Device. + * + * @returns {String} "Device 0.0.0" + * @api public + */ +Device.prototype.toString = function toString() { + var output = this.family + , version = this.toVersion(); + + if (version) output += ' '+ version; + return output; +}; + +/** + * Generates the version of the Device. + * + * @returns {String} + * @api public + */ +Device.prototype.toVersion = function toVersion() { + var version = ''; + + if (this.major) { + version += this.major; + + if (this.minor) { + version += '.' + this.minor; + + // Special case here, the patch can also be Alpha, Beta etc so we need + // to check if it's a string or not. + if (this.patch) { + version += (isNaN(+this.patch) ? ' ' : '.') + this.patch; + } + } + } + + return version; +}; + +/** + * Get string representation. + * + * @returns {String} + * @api public + */ +Device.prototype.toString = function toString() { + var output = this.family + , version = this.toVersion(); + + if (version) output += ' '+ version; + return output; +}; + +/** + * Outputs a JSON string of the Device, values are defaulted to undefined so they + * are not outputed in the stringify. + * + * @returns {String} + * @api public + */ +Device.prototype.toJSON = function toJSON() { + return { + family: this.family + , major: this.major || undefined + , minor: this.minor || undefined + , patch: this.patch || undefined + }; +}; + +/** + * Small nifty thick that allows us to download a fresh set regexs from t3h + * Int3rNetz when we want to. We will be using the compiled version by default + * but users can opt-in for updates. + * + * @param {Boolean} refresh Refresh the dataset from the remote + * @api public + */ +module.exports = function updater() { + try { + require('./lib/update').update(function updating(err, results) { + if (err) { + console.log('[useragent] Failed to update the parsed due to an error:'); + console.log('[useragent] '+ (err.message ? err.message : err)); + return; + } + + regexps = results; + + // OperatingSystem parsers: + osparsers = regexps.os; + osparserslength = osparsers.length; + + // UserAgent parsers: + agentparsers = regexps.browser; + agentparserslength = agentparsers.length; + + // Device parsers: + deviceparsers = regexps.device; + deviceparserslength = deviceparsers.length; + }); + } catch (e) { + console.error('[useragent] If you want to use automatic updating, please add:'); + console.error('[useragent] - request (npm install request --save)'); + console.error('[useragent] - yamlparser (npm install yamlparser --save)'); + console.error('[useragent] To your own package.json'); + } +}; + +// Override the exports with our newly set module.exports +exports = module.exports; + +/** + * Nao that we have setup all the different classes and configured it we can + * actually start assembling and exposing everything. + */ +exports.Device = Device; +exports.OperatingSystem = OperatingSystem; +exports.Agent = Agent; + +/** + * Parses the user agent string with the generated parsers from the + * ua-parser project on google code. + * + * @param {String} userAgent The user agent string + * @param {String} jsAgent Optional UA from js to detect chrome frame + * @returns {Agent} + * @api public + */ +exports.parse = function parse(userAgent, jsAgent) { + if (!userAgent) return new Agent(); + + var length = agentparserslength + , parsers = agentparsers + , i = 0 + , parser + , res; + + for (; i < length; i++) { + if (res = parsers[i][0].exec(userAgent)) { + parser = parsers[i]; + + if (parser[1]) res[1] = parser[1].replace('$1', res[1]); + if (!jsAgent) return new Agent( + res[1] + , parser[2] || res[2] + , parser[3] || res[3] + , parser[4] || res[4] + , userAgent + ); + + break; + } + } + + // Return early if we didn't find an match, but might still be able to parse + // the os and device, so make sure we supply it with the source + if (!parser || !res) return new Agent('', '', '', '', userAgent); + + // Detect Chrome Frame, but make sure it's enabled! So we need to check for + // the Chrome/ so we know that it's actually using Chrome under the hood. + if (jsAgent && ~jsAgent.indexOf('Chrome/') && ~userAgent.indexOf('chromeframe')) { + res[1] = 'Chrome Frame (IE '+ res[1] +'.'+ res[2] +')'; + + // Run the JavaScripted userAgent string through the parser again so we can + // update the version numbers; + parser = parse(jsAgent); + parser[2] = parser.major; + parser[3] = parser.minor; + parser[4] = parser.patch; + } + + return new Agent( + res[1] + , parser[2] || res[2] + , parser[3] || res[3] + , parser[4] || res[4] + , userAgent + ); +}; + +/** + * If you are doing a lot of lookups you might want to cache the results of the + * parsed user agent string instead, in memory. + * + * @TODO We probably want to create 2 dictionary's here 1 for the Agent + * instances and one for the userAgent instance mapping so we can re-use simular + * Agent instance and lower our memory consumption. + * + * @param {String} userAgent The user agent string + * @param {String} jsAgent Optional UA from js to detect chrome frame + * @api public + */ +var LRU = require('lru-cache')(5000); +exports.lookup = function lookup(userAgent, jsAgent) { + var key = (userAgent || '')+(jsAgent || '') + , cached = LRU.get(key); + + if (cached) return cached; + LRU.set(key, (cached = exports.parse(userAgent, jsAgent))); + + return cached; +}; + +/** + * Does a more inaccurate but more common check for useragents identification. + * The version detection is from the jQuery.com library and is licensed under + * MIT. + * + * @param {String} useragent The user agent + * @returns {Object} matches + * @api public + */ +exports.is = function is(useragent) { + var ua = (useragent || '').toLowerCase() + , details = { + chrome: false + , firefox: false + , ie: false + , mobile_safari: false + , mozilla: false + , opera: false + , safari: false + , webkit: false + , version: (ua.match(exports.is.versionRE) || [0, "0"])[1] + }; + + if (~ua.indexOf('webkit')) { + details.webkit = true; + + if (~ua.indexOf('chrome')) { + details.chrome = true; + } else if (~ua.indexOf('safari')) { + details.safari = true; + + if (~ua.indexOf('mobile') && ~ua.indexOf('apple')) { + details.mobile_safari = true; + } + } + } else if (~ua.indexOf('opera')) { + details.opera = true; + } else if (~ua.indexOf('mozilla') && !~ua.indexOf('compatible')) { + details.mozilla = true; + + if (~ua.indexOf('firefox')) details.firefox = true; + } else if (~ua.indexOf('msie')) { + details.ie = true; + } + + return details; +}; + +/** + * Parses out the version numbers. + * + * @type {RegExp} + * @api private + */ +exports.is.versionRE = /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/; + +/** + * Transform a JSON object back to a valid userAgent string + * + * @param {Object} details + * @returns {Agent} + */ +exports.fromJSON = function fromJSON(details) { + if (typeof details === 'string') details = JSON.parse(details); + + var agent = new Agent(details.family, details.major, details.minor, details.patch) + , os = details.os; + + // The device family was added in v2.0 + if ('device' in details) { + agent.device = new Device(details.device.family); + } else { + agent.device = new Device(); + } + + if ('os' in details && os) { + // In v1.1.0 we only parsed out the Operating System name, not the full + // version which we added in v2.0. To provide backwards compatible we should + // we should set the details.os as family + if (typeof os === 'string') { + agent.os = new OperatingSystem(os); + } else { + agent.os = new OperatingSystem(os.family, os.major, os.minor, os.patch); + } + } + + return agent; +}; + +/** + * Library version. + * + * @type {String} + * @api public + */ +exports.version = require('./package.json').version; diff --git a/node_modules/karma/node_modules/useragent/lib/regexps.js b/node_modules/karma/node_modules/useragent/lib/regexps.js new file mode 100644 index 00000000..fb271d4c --- /dev/null +++ b/node_modules/karma/node_modules/useragent/lib/regexps.js @@ -0,0 +1,2270 @@ +var parser; + +exports.browser = Object.create(null); + +parser = Object.create(null); +parser[0] = new RegExp("(SeaMonkey|Camino)/(\\d+)\\.(\\d+)\\.?([ab]?\\d+[a-z]*)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[0] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Pale[Mm]oon)/(\\d+)\\.(\\d+)\\.?(\\d+)?"); +parser[1] = "Pale Moon (Firefox Variant)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[1] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Fennec)/(\\d+)\\.(\\d+)\\.?([ab]?\\d+[a-z]*)"); +parser[1] = "Firefox Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[2] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Fennec)/(\\d+)\\.(\\d+)(pre)"); +parser[1] = "Firefox Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[3] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Fennec)/(\\d+)\\.(\\d+)"); +parser[1] = "Firefox Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[4] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Mobile.*(Firefox)/(\\d+)\\.(\\d+)"); +parser[1] = "Firefox Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[5] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Namoroka|Shiretoko|Minefield)/(\\d+)\\.(\\d+)\\.(\\d+(?:pre)?)"); +parser[1] = "Firefox ($1)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[6] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)(a\\d+[a-z]*)"); +parser[1] = "Firefox Alpha"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[7] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)(b\\d+[a-z]*)"); +parser[1] = "Firefox Beta"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[8] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)-(?:\\d+\\.\\d+)?/(\\d+)\\.(\\d+)(a\\d+[a-z]*)"); +parser[1] = "Firefox Alpha"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[9] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)-(?:\\d+\\.\\d+)?/(\\d+)\\.(\\d+)(b\\d+[a-z]*)"); +parser[1] = "Firefox Beta"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[10] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Namoroka|Shiretoko|Minefield)/(\\d+)\\.(\\d+)([ab]\\d+[a-z]*)?"); +parser[1] = "Firefox ($1)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[11] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox).*Tablet browser (\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "MicroB"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[12] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(MozillaDeveloperPreview)/(\\d+)\\.(\\d+)([ab]\\d+[a-z]*)?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[13] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Flock)/(\\d+)\\.(\\d+)(b\\d+?)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[14] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(RockMelt)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[15] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Navigator)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Netscape"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[16] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Navigator)/(\\d+)\\.(\\d+)([ab]\\d+)"); +parser[1] = "Netscape"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[17] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Netscape6)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Netscape"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[18] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(MyIBrow)/(\\d+)\\.(\\d+)"); +parser[1] = "My Internet Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[19] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Opera Tablet).*Version/(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[20] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Opera)/.+Opera Mobi.+Version/(\\d+)\\.(\\d+)"); +parser[1] = "Opera Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[21] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Opera Mobi"); +parser[1] = "Opera Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[22] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Opera Mini)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[23] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Opera Mini)/att/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[24] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Opera)/9.80.*Version/(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[25] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(?:Mobile Safari).*(OPR)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Opera Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[26] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(?:Chrome).*(OPR)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Opera"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[27] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(hpw|web)OS/(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = "webOS Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[28] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(luakit)"); +parser[1] = "LuaKit"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[29] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Snowshoe)/(\\d+)\\.(\\d+).(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[30] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Lightning)/(\\d+)\\.(\\d+)([ab]?\\d+[a-z]*)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[31] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)\\.(\\d+(?:pre)?) \\(Swiftfox\\)"); +parser[1] = "Swiftfox"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[32] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)([ab]\\d+[a-z]*)? \\(Swiftfox\\)"); +parser[1] = "Swiftfox"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[33] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(rekonq)/(\\d+)\\.(\\d+)\\.?(\\d+)? Safari"); +parser[1] = "Rekonq"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[34] = parser; +parser = Object.create(null); +parser[0] = new RegExp("rekonq"); +parser[1] = "Rekonq"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[35] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(conkeror|Conkeror)/(\\d+)\\.(\\d+)\\.?(\\d+)?"); +parser[1] = "Conkeror"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[36] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(konqueror)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Konqueror"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[37] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(WeTab)-Browser"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[38] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Comodo_Dragon)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Comodo Dragon"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[39] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(YottaaMonitor|BrowserMob|HttpMonitor|YandexBot|Slurp|BingPreview|PagePeeker|ThumbShotsBot|WebThumb|URL2PNG|ZooShot|GomezA|Catchpoint bot|Willow Internet Crawler|Google SketchUp|Read%20Later)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[40] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Symphony) (\\d+).(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[41] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Minimo)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[42] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(CrMo)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Chrome Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[43] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(CriOS)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Chrome Mobile iOS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[44] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Chrome)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+) Mobile"); +parser[1] = "Chrome Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[45] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(chromeframe)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Chrome Frame"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[46] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(UCBrowser)[ /](\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "UC Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[47] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(UC Browser)[ /](\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[48] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(UC Browser|UCBrowser|UCWEB)(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "UC Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[49] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(SLP Browser)/(\\d+)\\.(\\d+)"); +parser[1] = "Tizen Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[50] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(SE 2\\.X) MetaSr (\\d+)\\.(\\d+)"); +parser[1] = "Sogou Explorer"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[51] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(baidubrowser)[/\\s](\\d+)"); +parser[1] = "Baidu Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[52] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(FlyFlow)/(\\d+)\\.(\\d+)"); +parser[1] = "Baidu Explorer"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[53] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Pingdom.com_bot_version_)(\\d+)\\.(\\d+)"); +parser[1] = "PingdomBot"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[54] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(facebookexternalhit)/(\\d+)\\.(\\d+)"); +parser[1] = "FacebookBot"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[55] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Twitterbot)/(\\d+)\\.(\\d+)"); +parser[1] = "TwitterBot"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[56] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Rackspace Monitoring)/(\\d+)\\.(\\d+)"); +parser[1] = "RackspaceBot"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[57] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PyAMF)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[58] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(YaBrowser)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Yandex Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[59] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Chrome)/(\\d+)\\.(\\d+)\\.(\\d+).* MRCHROME"); +parser[1] = "Mail.ru Chromium Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[60] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AOL) (\\d+)\\.(\\d+); AOLBuild (\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[61] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AdobeAIR|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Epiphany|Shiira|Sunrise|Flock|Netscape|Lunascape|WebPilot|Vodafone|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iris|UP\\.Browser|Bunjalloo|Google Earth|Raven for Mac|Openwave)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[62] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Chromium|Chrome)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[63] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Bolt|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Chrome|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|Vodafone|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|NetNewsWire|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris|Abrowser|Planetweb|ICE Browser)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[64] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Chromium|Chrome)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[65] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[66] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iCab|Lunascape|Opera|Android|Jasmine|Polaris) (\\d+)\\.(\\d+)\\.?(\\d+)?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[67] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Kindle)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[68] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Donut"); +parser[1] = 0; +parser[2] = "1"; +parser[3] = "2"; +parser[4] = 0; +exports.browser[69] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Eclair"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "1"; +parser[4] = 0; +exports.browser[70] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Froyo"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "2"; +parser[4] = 0; +exports.browser[71] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Gingerbread"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "3"; +parser[4] = 0; +exports.browser[72] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Honeycomb"); +parser[1] = 0; +parser[2] = "3"; +parser[3] = 0; +parser[4] = 0; +exports.browser[73] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(IEMobile)[ /](\\d+)\\.(\\d+)"); +parser[1] = "IE Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[74] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(MSIE) (\\d+)\\.(\\d+).*XBLWP7"); +parser[1] = "IE Large Screen"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[75] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[76] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)(pre|[ab]\\d+[a-z]*)?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[77] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Obigo)InternetBrowser"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[78] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Obigo)\\-Browser"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[79] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Obigo|OBIGO)[^\\d]*(\\d+)(?:.(\\d+))?"); +parser[1] = "Obigo"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[80] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(MAXTHON|Maxthon) (\\d+)\\.(\\d+)"); +parser[1] = "Maxthon"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[81] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Maxthon|MyIE2|Uzbl|Shiira)"); +parser[1] = 0; +parser[2] = "0"; +parser[3] = 0; +parser[4] = 0; +exports.browser[82] = parser; +parser = Object.create(null); +parser[0] = new RegExp("PLAYSTATION 3.+WebKit"); +parser[1] = "NetFront NX"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[83] = parser; +parser = Object.create(null); +parser[0] = new RegExp("PLAYSTATION 3"); +parser[1] = "NetFront"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[84] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayStation Portable)"); +parser[1] = "NetFront"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[85] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayStation Vita)"); +parser[1] = "NetFront NX"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[86] = parser; +parser = Object.create(null); +parser[0] = new RegExp("AppleWebKit.+ (NX)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "NetFront NX"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[87] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Nintendo 3DS)"); +parser[1] = "NetFront NX"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[88] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BrowseX) \\((\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[89] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(NCSA_Mosaic)/(\\d+)\\.(\\d+)"); +parser[1] = "NCSA Mosaic"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[90] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(POLARIS)/(\\d+)\\.(\\d+)"); +parser[1] = "Polaris"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[91] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Embider)/(\\d+)\\.(\\d+)"); +parser[1] = "Polaris"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[92] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BonEcho)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Bon Echo"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[93] = parser; +parser = Object.create(null); +parser[0] = new RegExp("M?QQBrowser"); +parser[1] = "QQ Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[94] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod).+Version/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[95] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod).*Version/(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[96] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone).*Version/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[97] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone).*Version/(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[98] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPad).*Version/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[99] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPad).*Version/(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[100] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod|iPhone|iPad);.*CPU.*OS (\\d+)(?:_\\d+)?_(\\d+).*Mobile"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[101] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod|iPhone|iPad)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[102] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AvantGo) (\\d+).(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[103] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(OneBrowser)/(\\d+).(\\d+)"); +parser[1] = "ONE Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[104] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Avant)"); +parser[1] = 0; +parser[2] = "1"; +parser[3] = 0; +parser[4] = 0; +exports.browser[105] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(QtCarBrowser)"); +parser[1] = 0; +parser[2] = "1"; +parser[3] = 0; +parser[4] = 0; +exports.browser[106] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iBrowser/Mini)(\\d+).(\\d+)"); +parser[1] = "iBrowser Mini"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[107] = parser; +parser = Object.create(null); +parser[0] = new RegExp("^(Nokia)"); +parser[1] = "Nokia Services (WAP) Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[108] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(NokiaBrowser)/(\\d+)\\.(\\d+).(\\d+)\\.(\\d+)"); +parser[1] = "Nokia Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[109] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(NokiaBrowser)/(\\d+)\\.(\\d+).(\\d+)"); +parser[1] = "Nokia Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[110] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(NokiaBrowser)/(\\d+)\\.(\\d+)"); +parser[1] = "Nokia Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[111] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BrowserNG)/(\\d+)\\.(\\d+).(\\d+)"); +parser[1] = "Nokia Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[112] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Series60)/5\\.0"); +parser[1] = "Nokia Browser"; +parser[2] = "7"; +parser[3] = "0"; +parser[4] = 0; +exports.browser[113] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Series60)/(\\d+)\\.(\\d+)"); +parser[1] = "Nokia OSS Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[114] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(S40OviBrowser)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Ovi Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[115] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Nokia)[EN]?(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[116] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BB10);"); +parser[1] = "BlackBerry WebKit"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[117] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayBook).+RIM Tablet OS (\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "BlackBerry WebKit"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[118] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Black[bB]erry).+Version/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "BlackBerry WebKit"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[119] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Black[bB]erry)\\s?(\\d+)"); +parser[1] = "BlackBerry"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[120] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(OmniWeb)/v(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[121] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Blazer)/(\\d+)\\.(\\d+)"); +parser[1] = "Palm Blazer"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[122] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Pre)/(\\d+)\\.(\\d+)"); +parser[1] = "Palm Pre"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[123] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(ELinks)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[124] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(ELinks) \\((\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[125] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Links) \\((\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[126] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(QtWeb) Internet Browser/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[127] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Silk)/(\\d+)\\.(\\d+)(?:\\.([0-9\\-]+))?"); +parser[1] = "Amazon Silk"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[128] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PhantomJS)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[129] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AppleWebKit)/(\\d+)\\.?(\\d+)?\\+ .* Safari"); +parser[1] = "WebKit Nightly"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[130] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Version)/(\\d+)\\.(\\d+)(?:\\.(\\d+))?.*Safari/"); +parser[1] = "Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[131] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Safari)/\\d+"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[132] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(OLPC)/Update(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[133] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(OLPC)/Update()\\.(\\d+)"); +parser[1] = 0; +parser[2] = "0"; +parser[3] = 0; +parser[4] = 0; +exports.browser[134] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(SEMC\\-Browser)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[135] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Teleca)"); +parser[1] = "Teleca Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[136] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Phantom)/V(\\d+)\\.(\\d+)"); +parser[1] = "Phantom Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[137] = parser; +parser = Object.create(null); +parser[0] = new RegExp("([MS]?IE) (\\d+)\\.(\\d+)"); +parser[1] = "IE"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[138] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Trident(.*)rv.(\\d+)\\.(\\d+)"); +parser[1] = "IE"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[139] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(python-requests)/(\\d+)\\.(\\d+)"); +parser[1] = "Python Requests"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[140] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Thunderbird)/(\\d+)\\.(\\d+)\\.?(\\d+)?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[141] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Wget)/(\\d+)\\.(\\d+)\\.?([ab]?\\d+[a-z]*)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[142] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(curl)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "cURL"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[143] = parser; + +exports.browser.length = 144; + +exports.device = Object.create(null); + +parser = Object.create(null); +parser[0] = new RegExp("HTC ([A-Z][a-z0-9]+) Build"); +parser[1] = "HTC $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[0] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HTC ([A-Z][a-z0-9 ]+) \\d+\\.\\d+\\.\\d+\\.\\d+"); +parser[1] = "HTC $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[1] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HTC_Touch_([A-Za-z0-9]+)"); +parser[1] = "HTC Touch ($1)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[2] = parser; +parser = Object.create(null); +parser[0] = new RegExp("USCCHTC(\\d+)"); +parser[1] = "HTC $1 (US Cellular)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[3] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Sprint APA(9292)"); +parser[1] = "HTC $1 (Sprint)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[4] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HTC ([A-Za-z0-9]+ [A-Z])"); +parser[1] = "HTC $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[5] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HTC[-_/\\s]([A-Za-z0-9]+)"); +parser[1] = "HTC $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[6] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(ADR[A-Za-z0-9]+)"); +parser[1] = "HTC $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[7] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(HTC)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[8] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(QtCarBrowser)"); +parser[1] = "Tesla Model S"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[9] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(SamsungSGHi560)"); +parser[1] = "Samsung SGHi560"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[10] = parser; +parser = Object.create(null); +parser[0] = new RegExp("SonyEricsson([A-Za-z0-9]+)/"); +parser[1] = "Ericsson $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[11] = parser; +parser = Object.create(null); +parser[0] = new RegExp("PLAYSTATION 3"); +parser[1] = "PlayStation 3"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[12] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayStation Portable)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[13] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayStation Vita)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[14] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KFOT Build)"); +parser[1] = "Kindle Fire"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[15] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KFTT Build)"); +parser[1] = "Kindle Fire HD"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[16] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KFJWI Build)"); +parser[1] = "Kindle Fire HD 8.9\" WiFi"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[17] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KFJWA Build)"); +parser[1] = "Kindle Fire HD 8.9\" 4G"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[18] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Kindle Fire)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[19] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Kindle)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[20] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Silk)/(\\d+)\\.(\\d+)(?:\\.([0-9\\-]+))?"); +parser[1] = "Kindle Fire"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[21] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+; [A-Za-z]{2}\\-[A-Za-z]{2}; WOWMobile (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[22] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+\\-update1; [A-Za-z]{2}\\-[A-Za-z]{2}; (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[23] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+\\.[\\d]+; [A-Za-z]{2}\\-[A-Za-z]{2}; (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[24] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+\\.[\\d]+;[A-Za-z]{2}\\-[A-Za-z]{2};(.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[25] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+; [A-Za-z]{2}\\-[A-Za-z]{2}; (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[26] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+\\.[\\d]+; (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[27] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+; (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[28] = parser; +parser = Object.create(null); +parser[0] = new RegExp("NokiaN([0-9]+)"); +parser[1] = "Nokia N$1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[29] = parser; +parser = Object.create(null); +parser[0] = new RegExp("NOKIA([A-Za-z0-9\\v-]+)"); +parser[1] = "Nokia $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[30] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Nokia([A-Za-z0-9\\v-]+)"); +parser[1] = "Nokia $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[31] = parser; +parser = Object.create(null); +parser[0] = new RegExp("NOKIA ([A-Za-z0-9\\-]+)"); +parser[1] = "Nokia $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[32] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Nokia ([A-Za-z0-9\\-]+)"); +parser[1] = "Nokia $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[33] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Lumia ([A-Za-z0-9\\-]+)"); +parser[1] = "Lumia $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[34] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Symbian"); +parser[1] = "Nokia"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[35] = parser; +parser = Object.create(null); +parser[0] = new RegExp("BB10; ([A-Za-z0-9\\- ]+)\\)"); +parser[1] = "BlackBerry $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[36] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayBook).+RIM Tablet OS"); +parser[1] = "BlackBerry Playbook"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[37] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Black[Bb]erry ([0-9]+);"); +parser[1] = "BlackBerry $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[38] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Black[Bb]erry([0-9]+)"); +parser[1] = "BlackBerry $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[39] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Black[Bb]erry;"); +parser[1] = "BlackBerry"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[40] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Pre)/(\\d+)\\.(\\d+)"); +parser[1] = "Palm Pre"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[41] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Pixi)/(\\d+)\\.(\\d+)"); +parser[1] = "Palm Pixi"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[42] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Touch[Pp]ad)/(\\d+)\\.(\\d+)"); +parser[1] = "HP TouchPad"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[43] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HPiPAQ([A-Za-z0-9]+)/(\\d+).(\\d+)"); +parser[1] = "HP iPAQ $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[44] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Palm([A-Za-z0-9]+)"); +parser[1] = "Palm $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[45] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Treo([A-Za-z0-9]+)"); +parser[1] = "Palm Treo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[46] = parser; +parser = Object.create(null); +parser[0] = new RegExp("webOS.*(P160UNA)/(\\d+).(\\d+)"); +parser[1] = "HP Veer"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[47] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AppleTV)"); +parser[1] = "AppleTV"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[48] = parser; +parser = Object.create(null); +parser[0] = new RegExp("AdsBot-Google-Mobile"); +parser[1] = "Spider"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[49] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Googlebot-Mobile/(\\d+).(\\d+)"); +parser[1] = "Spider"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[50] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPad) Simulator;"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[51] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPad);"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[52] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod) touch;"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[53] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod);"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[54] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone) Simulator;"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[55] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone);"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[56] = parser; +parser = Object.create(null); +parser[0] = new RegExp("acer_([A-Za-z0-9]+)_"); +parser[1] = "Acer $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[57] = parser; +parser = Object.create(null); +parser[0] = new RegExp("acer_([A-Za-z0-9]+)_"); +parser[1] = "Acer $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[58] = parser; +parser = Object.create(null); +parser[0] = new RegExp("ALCATEL-([A-Za-z0-9]+)"); +parser[1] = "Alcatel $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[59] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Alcatel-([A-Za-z0-9]+)"); +parser[1] = "Alcatel $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[60] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Amoi\\-([A-Za-z0-9]+)"); +parser[1] = "Amoi $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[61] = parser; +parser = Object.create(null); +parser[0] = new RegExp("AMOI\\-([A-Za-z0-9]+)"); +parser[1] = "Amoi $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[62] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Asus\\-([A-Za-z0-9]+)"); +parser[1] = "Asus $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[63] = parser; +parser = Object.create(null); +parser[0] = new RegExp("ASUS\\-([A-Za-z0-9]+)"); +parser[1] = "Asus $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[64] = parser; +parser = Object.create(null); +parser[0] = new RegExp("BIRD\\-([A-Za-z0-9]+)"); +parser[1] = "Bird $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[65] = parser; +parser = Object.create(null); +parser[0] = new RegExp("BIRD\\.([A-Za-z0-9]+)"); +parser[1] = "Bird $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[66] = parser; +parser = Object.create(null); +parser[0] = new RegExp("BIRD ([A-Za-z0-9]+)"); +parser[1] = "Bird $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[67] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Dell ([A-Za-z0-9]+)"); +parser[1] = "Dell $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[68] = parser; +parser = Object.create(null); +parser[0] = new RegExp("DoCoMo/2\\.0 ([A-Za-z0-9]+)"); +parser[1] = "DoCoMo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[69] = parser; +parser = Object.create(null); +parser[0] = new RegExp("([A-Za-z0-9]+)_W\\;FOMA"); +parser[1] = "DoCoMo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[70] = parser; +parser = Object.create(null); +parser[0] = new RegExp("([A-Za-z0-9]+)\\;FOMA"); +parser[1] = "DoCoMo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[71] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Huawei([A-Za-z0-9]+)"); +parser[1] = "Huawei $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[72] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HUAWEI-([A-Za-z0-9]+)"); +parser[1] = "Huawei $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[73] = parser; +parser = Object.create(null); +parser[0] = new RegExp("vodafone([A-Za-z0-9]+)"); +parser[1] = "Huawei Vodafone $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[74] = parser; +parser = Object.create(null); +parser[0] = new RegExp("i\\-mate ([A-Za-z0-9]+)"); +parser[1] = "i-mate $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[75] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Kyocera\\-([A-Za-z0-9]+)"); +parser[1] = "Kyocera $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[76] = parser; +parser = Object.create(null); +parser[0] = new RegExp("KWC\\-([A-Za-z0-9]+)"); +parser[1] = "Kyocera $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[77] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Lenovo\\-([A-Za-z0-9]+)"); +parser[1] = "Lenovo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[78] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Lenovo_([A-Za-z0-9]+)"); +parser[1] = "Lenovo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[79] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LG/([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[80] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LG-LG([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[81] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LGE-LG([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[82] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LGE VX([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[83] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LG ([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[84] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LGE LG\\-AX([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[85] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LG\\-([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[86] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LGE\\-([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[87] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LG([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[88] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KIN)\\.One (\\d+)\\.(\\d+)"); +parser[1] = "Microsoft $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[89] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KIN)\\.Two (\\d+)\\.(\\d+)"); +parser[1] = "Microsoft $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[90] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Motorola)\\-([A-Za-z0-9]+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[91] = parser; +parser = Object.create(null); +parser[0] = new RegExp("MOTO\\-([A-Za-z0-9]+)"); +parser[1] = "Motorola $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[92] = parser; +parser = Object.create(null); +parser[0] = new RegExp("MOT\\-([A-Za-z0-9]+)"); +parser[1] = "Motorola $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[93] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Nintendo WiiU)"); +parser[1] = "Nintendo Wii U"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[94] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Nintendo (DS|3DS|DSi|Wii);"); +parser[1] = "Nintendo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[95] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Pantech([A-Za-z0-9]+)"); +parser[1] = "Pantech $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[96] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Philips([A-Za-z0-9]+)"); +parser[1] = "Philips $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[97] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Philips ([A-Za-z0-9]+)"); +parser[1] = "Philips $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[98] = parser; +parser = Object.create(null); +parser[0] = new RegExp("SAMSUNG-([A-Za-z0-9\\-]+)"); +parser[1] = "Samsung $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[99] = parser; +parser = Object.create(null); +parser[0] = new RegExp("SAMSUNG\\; ([A-Za-z0-9\\-]+)"); +parser[1] = "Samsung $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[100] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Dreamcast"); +parser[1] = "Sega Dreamcast"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[101] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Softbank/1\\.0/([A-Za-z0-9]+)"); +parser[1] = "Softbank $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[102] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Softbank/2\\.0/([A-Za-z0-9]+)"); +parser[1] = "Softbank $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[103] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(WebTV)/(\\d+).(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[104] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(hiptop|avantgo|plucker|xiino|blazer|elaine|up.browser|up.link|mmp|smartphone|midp|wap|vodafone|o2|pocket|mobile|pda)"); +parser[1] = "Generic Smartphone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[105] = parser; +parser = Object.create(null); +parser[0] = new RegExp("^(1207|3gso|4thp|501i|502i|503i|504i|505i|506i|6310|6590|770s|802s|a wa|acer|acs\\-|airn|alav|asus|attw|au\\-m|aur |aus |abac|acoo|aiko|alco|alca|amoi|anex|anny|anyw|aptu|arch|argo|bell|bird|bw\\-n|bw\\-u|beck|benq|bilb|blac|c55/|cdm\\-|chtm|capi|comp|cond|craw|dall|dbte|dc\\-s|dica|ds\\-d|ds12|dait|devi|dmob|doco|dopo|el49|erk0|esl8|ez40|ez60|ez70|ezos|ezze|elai|emul|eric|ezwa|fake|fly\\-|fly_|g\\-mo|g1 u|g560|gf\\-5|grun|gene|go.w|good|grad|hcit|hd\\-m|hd\\-p|hd\\-t|hei\\-|hp i|hpip|hs\\-c|htc |htc\\-|htca|htcg)"); +parser[1] = "Generic Feature Phone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[106] = parser; +parser = Object.create(null); +parser[0] = new RegExp("^(htcp|htcs|htct|htc_|haie|hita|huaw|hutc|i\\-20|i\\-go|i\\-ma|i230|iac|iac\\-|iac/|ig01|im1k|inno|iris|jata|java|kddi|kgt|kgt/|kpt |kwc\\-|klon|lexi|lg g|lg\\-a|lg\\-b|lg\\-c|lg\\-d|lg\\-f|lg\\-g|lg\\-k|lg\\-l|lg\\-m|lg\\-o|lg\\-p|lg\\-s|lg\\-t|lg\\-u|lg\\-w|lg/k|lg/l|lg/u|lg50|lg54|lge\\-|lge/|lynx|leno|m1\\-w|m3ga|m50/|maui|mc01|mc21|mcca|medi|meri|mio8|mioa|mo01|mo02|mode|modo|mot |mot\\-|mt50|mtp1|mtv |mate|maxo|merc|mits|mobi|motv|mozz|n100|n101|n102|n202|n203|n300|n302|n500|n502|n505|n700|n701|n710|nec\\-|nem\\-|newg|neon)"); +parser[1] = "Generic Feature Phone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[107] = parser; +parser = Object.create(null); +parser[0] = new RegExp("^(netf|noki|nzph|o2 x|o2\\-x|opwv|owg1|opti|oran|ot\\-s|p800|pand|pg\\-1|pg\\-2|pg\\-3|pg\\-6|pg\\-8|pg\\-c|pg13|phil|pn\\-2|pt\\-g|palm|pana|pire|pock|pose|psio|qa\\-a|qc\\-2|qc\\-3|qc\\-5|qc\\-7|qc07|qc12|qc21|qc32|qc60|qci\\-|qwap|qtek|r380|r600|raks|rim9|rove|s55/|sage|sams|sc01|sch\\-|scp\\-|sdk/|se47|sec\\-|sec0|sec1|semc|sgh\\-|shar|sie\\-|sk\\-0|sl45|slid|smb3|smt5|sp01|sph\\-|spv |spv\\-|sy01|samm|sany|sava|scoo|send|siem|smar|smit|soft|sony|t\\-mo|t218|t250|t600|t610|t618|tcl\\-|tdg\\-|telm|tim\\-|ts70|tsm\\-|tsm3|tsm5|tx\\-9|tagt)"); +parser[1] = "Generic Feature Phone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[108] = parser; +parser = Object.create(null); +parser[0] = new RegExp("^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vite|voda|vulc|w3c |w3c\\-|wapj|wapp|wapu|wapm|wig |wapi|wapr|wapv|wapy|wapa|waps|wapt|winc|winw|wonu|x700|xda2|xdag|yas\\-|your|zte\\-|zeto|aste|audi|avan|blaz|brew|brvw|bumb|ccwa|cell|cldc|cmd\\-|dang|eml2|fetc|hipt|http|ibro|idea|ikom|ipaq|jbro|jemu|jigs|keji|kyoc|kyok|libw|m\\-cr|midp|mmef|moto|mwbp|mywa|newt|nok6|o2im|pant|pdxg|play|pluc|port|prox|rozo|sama|seri|smal|symb|treo|upsi|vx52|vx53|vx60|vx61|vx70|vx80|vx81|vx83|vx85|wap\\-|webc|whit|wmlb|xda\\-|xda_)"); +parser[1] = "Generic Feature Phone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[109] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(bot|borg|google(^tv)|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|lycos|scooter|altavista|teoma|gigabot|baiduspider|blitzbot|oegp|charlotte|furlbot|http%20client|polybot|htdig|ichiro|mogimogi|larbin|pompos|scrubby|searchsight|seekbot|semanticdiscovery|silk|snappy|speedy|spider|voila|vortex|voyager|zao|zeal|fast\\-webcrawler|converacrawler|dataparksearch|findlinks|crawler)"); +parser[1] = "Spider"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[110] = parser; + +exports.device.length = 111; + +exports.os = Object.create(null); + +parser = Object.create(null); +parser[0] = new RegExp("(Android) (\\d+)\\.(\\d+)(?:[.\\-]([a-z0-9]+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[0] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android)\\-(\\d+)\\.(\\d+)(?:[.\\-]([a-z0-9]+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[1] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Donut"); +parser[1] = 0; +parser[2] = "1"; +parser[3] = "2"; +parser[4] = 0; +exports.os[2] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Eclair"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "1"; +parser[4] = 0; +exports.os[3] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Froyo"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "2"; +parser[4] = 0; +exports.os[4] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Gingerbread"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "3"; +parser[4] = 0; +exports.os[5] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Honeycomb"); +parser[1] = 0; +parser[2] = "3"; +parser[3] = 0; +parser[4] = 0; +exports.os[6] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Silk-Accelerated=[a-z]{4,5})"); +parser[1] = "Android"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[7] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows (?:NT 5\\.2|NT 5\\.1))"); +parser[1] = "Windows XP"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[8] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(XBLWP7)"); +parser[1] = "Windows Phone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[9] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows NT 6\\.1)"); +parser[1] = "Windows 7"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[10] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows NT 6\\.0)"); +parser[1] = "Windows Vista"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[11] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Win 9x 4\\.90)"); +parser[1] = "Windows Me"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[12] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\\.0|Windows Vista|Windows 2000|Windows 3.1)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[13] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows NT 6\\.2; ARM;)"); +parser[1] = "Windows RT"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[14] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows NT 6\\.2)"); +parser[1] = "Windows 8"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[15] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows NT 5\\.0)"); +parser[1] = "Windows 2000"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[16] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows Phone) (\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[17] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows Phone) OS (\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[18] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows ?Mobile)"); +parser[1] = "Windows Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[19] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(WinNT4.0)"); +parser[1] = "Windows NT 4.0"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[20] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Win98)"); +parser[1] = "Windows 98"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[21] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Tizen)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[22] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Mac OS X) (\\d+)[_.](\\d+)(?:[_.](\\d+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[23] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Mac_PowerPC"); +parser[1] = "Mac OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[24] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(?:PPC|Intel) (Mac OS X)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[25] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(CPU OS|iPhone OS) (\\d+)_(\\d+)(?:_(\\d+))?"); +parser[1] = "iOS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[26] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone|iPad|iPod); Opera"); +parser[1] = "iOS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[27] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone|iPad|iPod).*Mac OS X.*Version/(\\d+)\\.(\\d+)"); +parser[1] = "iOS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[28] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AppleTV)/(\\d+)\\.(\\d+)"); +parser[1] = "ATV OS X"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[29] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(CrOS) [a-z0-9_]+ (\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = "Chrome OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[30] = parser; +parser = Object.create(null); +parser[0] = new RegExp("([Dd]ebian)"); +parser[1] = "Debian"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[31] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Linux Mint)(?:/(\\d+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[32] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Mandriva)(?: Linux)?/(?:[\\d.-]+m[a-z]{2}(\\d+).(\\d))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[33] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Symbian[Oo][Ss])/(\\d+)\\.(\\d+)"); +parser[1] = "Symbian OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[34] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Symbian/3).+NokiaBrowser/7\\.3"); +parser[1] = "Symbian^3 Anna"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[35] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Symbian/3).+NokiaBrowser/7\\.4"); +parser[1] = "Symbian^3 Belle"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[36] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Symbian/3)"); +parser[1] = "Symbian^3"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[37] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Series 60|SymbOS|S60)"); +parser[1] = "Symbian OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[38] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(MeeGo)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[39] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Symbian [Oo][Ss]"); +parser[1] = "Symbian OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[40] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Series40;"); +parser[1] = "Nokia Series 40"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[41] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BB10);.+Version/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "BlackBerry OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[42] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Black[Bb]erry)[0-9a-z]+/(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = "BlackBerry OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[43] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Black[Bb]erry).+Version/(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = "BlackBerry OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[44] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(RIM Tablet OS) (\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "BlackBerry Tablet OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[45] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Play[Bb]ook)"); +parser[1] = "BlackBerry Tablet OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[46] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Black[Bb]erry)"); +parser[1] = "BlackBerry OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[47] = parser; +parser = Object.create(null); +parser[0] = new RegExp("\\(Mobile;.+Firefox/\\d+\\.\\d+"); +parser[1] = "Firefox OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[48] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BREW)[ /](\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[49] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BREW);"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[50] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Brew MP|BMP)[ /](\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Brew MP"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[51] = parser; +parser = Object.create(null); +parser[0] = new RegExp("BMP;"); +parser[1] = "Brew MP"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[52] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(GoogleTV) (\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[53] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(GoogleTV)/[\\da-z]+"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[54] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(WebTV)/(\\d+).(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[55] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(hpw|web)OS/(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = "webOS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[56] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(VRE);"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[57] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Fedora|Red Hat|PCLinuxOS)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[58] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Red Hat|Puppy|PCLinuxOS)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[59] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Red Hat|Slackware)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[60] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows|OpenBSD|FreeBSD|NetBSD|Android|WeTab)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[61] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Gentoo|Mageia)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[62] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Linux)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[63] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Linux|BSD)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[64] = parser; +parser = Object.create(null); +parser[0] = new RegExp("SunOS"); +parser[1] = "Solaris"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[65] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Red Hat)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[66] = parser; + +exports.os.length = 67; \ No newline at end of file diff --git a/node_modules/karma/node_modules/useragent/lib/update.js b/node_modules/karma/node_modules/useragent/lib/update.js new file mode 100644 index 00000000..eb05092f --- /dev/null +++ b/node_modules/karma/node_modules/useragent/lib/update.js @@ -0,0 +1,202 @@ +'use strict'; + +/** + * Build in Native modules. + */ +var path = require('path') + , fs = require('fs') + , vm = require('vm'); + +/** + * Third party modules. + */ +var request = require('request') + , yaml = require('yamlparser'); + +exports.update = function update(callback) { + // Fetch the remote resource as that is frequently updated + request(exports.remote, function downloading(err, res, remote) { + if (err) return callback(err); + if (res.statusCode !== 200) return callback(new Error('Invalid statusCode returned')); + + // Also get some local additions that are missing from the source + fs.readFile(exports.local, 'utf8', function reading(err, local) { + if (err) return callback(err); + + // Parse the contents + exports.parse([ remote, local ], function parsing(err, results, source) { + callback(err, results); + + if (source && !err) { + fs.writeFile(exports.output, source, function idk(err) { + if (err) { + console.error('Failed to save the generated file due to reasons', err); + } + }); + } + }); + }); + }); +}; + +exports.parse = function parse(sources, callback) { + var results = {}; + + var data = sources.reduce(function parser(memo, data) { + // Try to repair some of the odd structures that are in the yaml files + // before parsing it so we generate a uniform structure: + + // Normalize the Operating system versions: + data = data.replace(/os_v([1-3])_replacement/gim, function replace(match, version) { + return 'v'+ version +'_replacement'; + }); + + // Make sure that we are able to parse the yaml string + try { data = yaml.eval(data); } + catch (e) { + callback(e); + callback = null; + return memo; + } + + // merge the data with the memo; + Object.keys(data).forEach(function (key) { + var results = data[key]; + memo[key] = memo[key] || []; + + for (var i = 0, l = results.length; i < l; i++) { + memo[key].push(results[i]); + } + }); + + return memo; + }, {}); + + [ + { + resource: 'user_agent_parsers' + , replacement: 'family_replacement' + , name: 'browser' + } + , { + resource: 'device_parsers' + , replacement: 'device_replacement' + , name: 'device' + } + , { + resource: 'os_parsers' + , replacement: 'os_replacement' + , name: 'os' + } + ].forEach(function parsing(details) { + results[details.resource] = results[details.resource] || []; + + var resources = data[details.resource] + , name = details.resource.replace('_parsers', '') + , resource + , parser; + + for (var i = 0, l = resources.length; i < l; i++) { + resource = resources[i]; + + // We need to JSON stringify the data to properly add slashes escape other + // kinds of crap in the RegularExpression. If we don't do thing we get + // some illegal token warnings. + parser = 'parser = Object.create(null);\n'; + parser += 'parser[0] = new RegExp('+ JSON.stringify(resource.regex) + ');\n'; + + // Check if we have replacement for the parsed family name + if (resource[details.replacement]) { + parser += 'parser[1] = "'+ resource[details.replacement].replace('"', '\\"') +'";'; + } else { + parser += 'parser[1] = 0;'; + } + + parser += '\n'; + + if (resource.v1_replacement) { + parser += 'parser[2] = "'+ resource.v1_replacement.replace('"', '\\"') +'";'; + } else { + parser += 'parser[2] = 0;'; + } + + parser += '\n'; + + if (resource.v2_replacement) { + parser += 'parser[3] = "'+ resource.v2_replacement.replace('"', '\\"') +'";'; + } else { + parser += 'parser[3] = 0;'; + } + + parser += '\n'; + + if (resource.v3_replacement) { + parser += 'parser[4] = "'+ resource.v3_replacement.replace('"', '\\"') +'";'; + } else { + parser += 'parser[4] = 0;'; + } + + parser += '\n'; + parser += 'exports.'+ details.name +'['+ i +'] = parser;'; + results[details.resource].push(parser); + } + }); + + // Generate a correct format + exports.generate(results, callback); +}; + +exports.generate = function generate(results, callback) { + var regexps = [ + 'var parser;' + , 'exports.browser = Object.create(null);' + , results.user_agent_parsers.join('\n') + , 'exports.browser.length = '+ results.user_agent_parsers.length +';' + + , 'exports.device = Object.create(null);' + , results.device_parsers.join('\n') + , 'exports.device.length = '+ results.device_parsers.length +';' + + , 'exports.os = Object.create(null);' + , results.os_parsers.join('\n') + , 'exports.os.length = '+ results.os_parsers.length +';' + ].join('\n\n'); + + // Now that we have generated the structure for the RegExps export file we + // need to validate that we created a JavaScript compatible file, if we would + // write the file without checking it's content we could be breaking the + // module. + var sandbox = { + exports: {} // Emulate a module context, so everything is attached here + }; + + // Crossing our fingers that it worked + try { vm.runInNewContext(regexps, sandbox, 'validating.vm'); } + catch (e) { return callback(e, null, regexps); } + + callback(undefined, sandbox.exports, regexps); +}; + +/** + * The location of the ua-parser regexes yaml file. + * + * @type {String} + * @api private + */ +exports.remote = 'https://raw.github.com/tobie/ua-parser/master/regexes.yaml'; + +/** + * The location of our local regexes yaml file. + * + * @type {String} + * @api private + */ +exports.local = path.resolve(__dirname, '..', 'static', 'user_agent.after.yaml'); + +/** + * The the output location for the generated regexps file + * + * @type {String} + * @api private + */ +exports.output = path.resolve(__dirname, '..', 'lib', 'regexps.js'); diff --git a/node_modules/karma/node_modules/useragent/node_modules/lru-cache/.npmignore b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/.npmignore new file mode 100644 index 00000000..07e6e472 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/.npmignore @@ -0,0 +1 @@ +/node_modules diff --git a/node_modules/karma/node_modules/useragent/node_modules/lru-cache/AUTHORS b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/AUTHORS new file mode 100644 index 00000000..016d7fbe --- /dev/null +++ b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/AUTHORS @@ -0,0 +1,8 @@ +# Authors, sorted by whether or not they are me +Isaac Z. Schlueter +Carlos Brito Lage +Marko Mikulicic +Trent Mick +Kevin O'Hara +Marco Rogers +Jesse Dailey diff --git a/node_modules/karma/node_modules/useragent/node_modules/lru-cache/LICENSE b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/LICENSE new file mode 100644 index 00000000..05a40109 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +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: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +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. diff --git a/node_modules/karma/node_modules/useragent/node_modules/lru-cache/README.md b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/README.md new file mode 100644 index 00000000..9aeb3164 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/README.md @@ -0,0 +1,88 @@ +# lru cache + +A cache object that deletes the least-recently-used items. + +## Usage: + +```javascript +var LRU = require("lru-cache") + , options = { max: 500 + , length: function (n) { return n * 2 } + , dispose: function (key, n) { n.close() } + , maxAge: 1000 * 60 * 60 } + , cache = LRU(options) + , otherCache = LRU(50) // sets just the max size + +cache.set("key", "value") +cache.get("key") // "value" + +cache.reset() // empty the cache +``` + +If you put more stuff in it, then items will fall out. + +If you try to put an oversized thing in it, then it'll fall out right +away. + +## Options + +* `max` The maximum size of the cache, checked by applying the length + function to all values in the cache. Not setting this is kind of + silly, since that's the whole purpose of this lib, but it defaults + to `Infinity`. +* `maxAge` Maximum age in ms. Items are not pro-actively pruned out + as they age, but if you try to get an item that is too old, it'll + drop it and return undefined instead of giving it to you. +* `length` Function that is used to calculate the length of stored + items. If you're storing strings or buffers, then you probably want + to do something like `function(n){return n.length}`. The default is + `function(n){return 1}`, which is fine if you want to store `n` + like-sized things. +* `dispose` Function that is called on items when they are dropped + from the cache. This can be handy if you want to close file + descriptors or do other cleanup tasks when items are no longer + accessible. Called with `key, value`. It's called *before* + actually removing the item from the internal cache, so if you want + to immediately put it back in, you'll have to do that in a + `nextTick` or `setTimeout` callback or it won't do anything. +* `stale` By default, if you set a `maxAge`, it'll only actually pull + stale items out of the cache when you `get(key)`. (That is, it's + not pre-emptively doing a `setTimeout` or anything.) If you set + `stale:true`, it'll return the stale value before deleting it. If + you don't set this, then it'll return `undefined` when you try to + get a stale entry, as if it had already been deleted. + +## API + +* `set(key, value)` +* `get(key) => value` + + Both of these will update the "recently used"-ness of the key. + They do what you think. + +* `del(key)` + + Deletes a key out of the cache. + +* `reset()` + + Clear the cache entirely, throwing away all values. + +* `has(key)` + + Check if a key is in the cache, without updating the recent-ness + or deleting it for being stale. + +* `forEach(function(value,key,cache), [thisp])` + + Just like `Array.prototype.forEach`. Iterates over all the keys + in the cache, in order of recent-ness. (Ie, more recently used + items are iterated over first.) + +* `keys()` + + Return an array of the keys in the cache. + +* `values()` + + Return an array of the values in the cache. diff --git a/node_modules/karma/node_modules/useragent/node_modules/lru-cache/lib/lru-cache.js b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/lib/lru-cache.js new file mode 100644 index 00000000..4ae51ac3 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/lib/lru-cache.js @@ -0,0 +1,242 @@ +;(function () { // closure for web browsers + +if (typeof module === 'object' && module.exports) { + module.exports = LRUCache +} else { + // just set the global for non-node platforms. + this.LRUCache = LRUCache +} + +function hOP (obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key) +} + +function naiveLength () { return 1 } + +function LRUCache (options) { + if (!(this instanceof LRUCache)) { + return new LRUCache(options) + } + + var max + if (typeof options === 'number') { + max = options + options = { max: max } + } + + if (!options) options = {} + + max = options.max + + var lengthCalculator = options.length || naiveLength + + if (typeof lengthCalculator !== "function") { + lengthCalculator = naiveLength + } + + if (!max || !(typeof max === "number") || max <= 0 ) { + // a little bit silly. maybe this should throw? + max = Infinity + } + + var allowStale = options.stale || false + + var maxAge = options.maxAge || null + + var dispose = options.dispose + + var cache = Object.create(null) // hash of items by key + , lruList = Object.create(null) // list of items in order of use recency + , mru = 0 // most recently used + , lru = 0 // least recently used + , length = 0 // number of items in the list + , itemCount = 0 + + + // resize the cache when the max changes. + Object.defineProperty(this, "max", + { set : function (mL) { + if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity + max = mL + // if it gets above double max, trim right away. + // otherwise, do it whenever it's convenient. + if (length > max) trim() + } + , get : function () { return max } + , enumerable : true + }) + + // resize the cache when the lengthCalculator changes. + Object.defineProperty(this, "lengthCalculator", + { set : function (lC) { + if (typeof lC !== "function") { + lengthCalculator = naiveLength + length = itemCount + for (var key in cache) { + cache[key].length = 1 + } + } else { + lengthCalculator = lC + length = 0 + for (var key in cache) { + cache[key].length = lengthCalculator(cache[key].value) + length += cache[key].length + } + } + + if (length > max) trim() + } + , get : function () { return lengthCalculator } + , enumerable : true + }) + + Object.defineProperty(this, "length", + { get : function () { return length } + , enumerable : true + }) + + + Object.defineProperty(this, "itemCount", + { get : function () { return itemCount } + , enumerable : true + }) + + this.forEach = function (fn, thisp) { + thisp = thisp || this + var i = 0; + for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) { + i++ + var hit = lruList[k] + fn.call(thisp, hit.value, hit.key, this) + } + } + + this.keys = function () { + var keys = new Array(itemCount) + var i = 0 + for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) { + var hit = lruList[k] + keys[i++] = hit.key + } + return keys + } + + this.values = function () { + var values = new Array(itemCount) + var i = 0 + for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) { + var hit = lruList[k] + values[i++] = hit.value + } + return values + } + + this.reset = function () { + if (dispose) { + for (var k in cache) { + dispose(k, cache[k].value) + } + } + cache = {} + lruList = {} + lru = 0 + mru = 0 + length = 0 + itemCount = 0 + } + + // Provided for debugging/dev purposes only. No promises whatsoever that + // this API stays stable. + this.dump = function () { + return cache + } + + this.dumpLru = function () { + return lruList + } + + this.set = function (key, value) { + if (hOP(cache, key)) { + // dispose of the old one before overwriting + if (dispose) dispose(key, cache[key].value) + if (maxAge) cache[key].now = Date.now() + cache[key].value = value + this.get(key) + return true + } + + var len = lengthCalculator(value) + var age = maxAge ? Date.now() : 0 + var hit = new Entry(key, value, mru++, len, age) + + // oversized objects fall out of cache automatically. + if (hit.length > max) { + if (dispose) dispose(key, value) + return false + } + + length += hit.length + lruList[hit.lu] = cache[key] = hit + itemCount ++ + + if (length > max) trim() + return true + } + + this.has = function (key) { + if (!hOP(cache, key)) return false + var hit = cache[key] + if (maxAge && (Date.now() - hit.now > maxAge)) { + return false + } + return true + } + + this.get = function (key) { + if (!hOP(cache, key)) return + var hit = cache[key] + if (maxAge && (Date.now() - hit.now > maxAge)) { + this.del(key) + return allowStale ? hit.value : undefined + } + shiftLU(hit) + hit.lu = mru ++ + lruList[hit.lu] = hit + return hit.value + } + + this.del = function (key) { + del(cache[key]) + } + + function trim () { + while (lru < mru && length > max) + del(lruList[lru]) + } + + function shiftLU(hit) { + delete lruList[ hit.lu ] + while (lru < mru && !lruList[lru]) lru ++ + } + + function del(hit) { + if (hit) { + if (dispose) dispose(hit.key, hit.value) + length -= hit.length + itemCount -- + delete cache[ hit.key ] + shiftLU(hit) + } + } +} + +// classy, since V8 prefers predictable objects. +function Entry (key, value, mru, len, age) { + this.key = key + this.value = value + this.lu = mru + this.length = len + this.now = age +} + +})() diff --git a/node_modules/karma/node_modules/useragent/node_modules/lru-cache/package.json b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/package.json new file mode 100644 index 00000000..229a2045 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/package.json @@ -0,0 +1,63 @@ +{ + "name": "lru-cache", + "description": "A cache object that deletes the least-recently-used items.", + "version": "2.2.4", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "scripts": { + "test": "tap test --gc" + }, + "main": "lib/lru-cache.js", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/node-lru-cache.git" + }, + "devDependencies": { + "tap": "", + "weak": "" + }, + "license": { + "type": "MIT", + "url": "http://github.com/isaacs/node-lru-cache/raw/master/LICENSE" + }, + "contributors": [ + { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + { + "name": "Carlos Brito Lage", + "email": "carlos@carloslage.net" + }, + { + "name": "Marko Mikulicic", + "email": "marko.mikulicic@isti.cnr.it" + }, + { + "name": "Trent Mick", + "email": "trentm@gmail.com" + }, + { + "name": "Kevin O'Hara", + "email": "kevinohara80@gmail.com" + }, + { + "name": "Marco Rogers", + "email": "marco.rogers@gmail.com" + }, + { + "name": "Jesse Dailey", + "email": "jesse.dailey@gmail.com" + } + ], + "readme": "# lru cache\n\nA cache object that deletes the least-recently-used items.\n\n## Usage:\n\n```javascript\nvar LRU = require(\"lru-cache\")\n , options = { max: 500\n , length: function (n) { return n * 2 }\n , dispose: function (key, n) { n.close() }\n , maxAge: 1000 * 60 * 60 }\n , cache = LRU(options)\n , otherCache = LRU(50) // sets just the max size\n\ncache.set(\"key\", \"value\")\ncache.get(\"key\") // \"value\"\n\ncache.reset() // empty the cache\n```\n\nIf you put more stuff in it, then items will fall out.\n\nIf you try to put an oversized thing in it, then it'll fall out right\naway.\n\n## Options\n\n* `max` The maximum size of the cache, checked by applying the length\n function to all values in the cache. Not setting this is kind of\n silly, since that's the whole purpose of this lib, but it defaults\n to `Infinity`.\n* `maxAge` Maximum age in ms. Items are not pro-actively pruned out\n as they age, but if you try to get an item that is too old, it'll\n drop it and return undefined instead of giving it to you.\n* `length` Function that is used to calculate the length of stored\n items. If you're storing strings or buffers, then you probably want\n to do something like `function(n){return n.length}`. The default is\n `function(n){return 1}`, which is fine if you want to store `n`\n like-sized things.\n* `dispose` Function that is called on items when they are dropped\n from the cache. This can be handy if you want to close file\n descriptors or do other cleanup tasks when items are no longer\n accessible. Called with `key, value`. It's called *before*\n actually removing the item from the internal cache, so if you want\n to immediately put it back in, you'll have to do that in a\n `nextTick` or `setTimeout` callback or it won't do anything.\n* `stale` By default, if you set a `maxAge`, it'll only actually pull\n stale items out of the cache when you `get(key)`. (That is, it's\n not pre-emptively doing a `setTimeout` or anything.) If you set\n `stale:true`, it'll return the stale value before deleting it. If\n you don't set this, then it'll return `undefined` when you try to\n get a stale entry, as if it had already been deleted.\n\n## API\n\n* `set(key, value)`\n* `get(key) => value`\n\n Both of these will update the \"recently used\"-ness of the key.\n They do what you think.\n\n* `del(key)`\n\n Deletes a key out of the cache.\n\n* `reset()`\n\n Clear the cache entirely, throwing away all values.\n\n* `has(key)`\n\n Check if a key is in the cache, without updating the recent-ness\n or deleting it for being stale.\n\n* `forEach(function(value,key,cache), [thisp])`\n\n Just like `Array.prototype.forEach`. Iterates over all the keys\n in the cache, in order of recent-ness. (Ie, more recently used\n items are iterated over first.)\n\n* `keys()`\n\n Return an array of the keys in the cache.\n\n* `values()`\n\n Return an array of the values in the cache.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/node-lru-cache/issues" + }, + "homepage": "https://github.com/isaacs/node-lru-cache", + "_id": "lru-cache@2.2.4", + "_from": "lru-cache@2.2.x" +} diff --git a/node_modules/karma/node_modules/useragent/node_modules/lru-cache/s.js b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/s.js new file mode 100644 index 00000000..c2a9e548 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/s.js @@ -0,0 +1,25 @@ +var LRU = require('lru-cache'); + +var max = +process.argv[2] || 10240; +var more = 1024; + +var cache = LRU({ + max: max, maxAge: 86400e3 +}); + +// fill cache +for (var i = 0; i < max; ++i) { + cache.set(i, {}); +} + +var start = process.hrtime(); + +// adding more items +for ( ; i < max+more; ++i) { + cache.set(i, {}); +} + +var end = process.hrtime(start); +var msecs = end[0] * 1E3 + end[1] / 1E6; + +console.log('adding %d items took %d ms', more, msecs.toPrecision(5)); diff --git a/node_modules/karma/node_modules/useragent/node_modules/lru-cache/test/basic.js b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/test/basic.js new file mode 100644 index 00000000..55d52633 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/test/basic.js @@ -0,0 +1,317 @@ +var test = require("tap").test + , LRU = require("../") + +test("basic", function (t) { + var cache = new LRU({max: 10}) + cache.set("key", "value") + t.equal(cache.get("key"), "value") + t.equal(cache.get("nada"), undefined) + t.equal(cache.length, 1) + t.equal(cache.max, 10) + t.end() +}) + +test("least recently set", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.set("b", "B") + cache.set("c", "C") + t.equal(cache.get("c"), "C") + t.equal(cache.get("b"), "B") + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("lru recently gotten", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.set("b", "B") + cache.get("a") + cache.set("c", "C") + t.equal(cache.get("c"), "C") + t.equal(cache.get("b"), undefined) + t.equal(cache.get("a"), "A") + t.end() +}) + +test("del", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.del("a") + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("max", function (t) { + var cache = new LRU(3) + + // test changing the max, verify that the LRU items get dropped. + cache.max = 100 + for (var i = 0; i < 100; i ++) cache.set(i, i) + t.equal(cache.length, 100) + for (var i = 0; i < 100; i ++) { + t.equal(cache.get(i), i) + } + cache.max = 3 + t.equal(cache.length, 3) + for (var i = 0; i < 97; i ++) { + t.equal(cache.get(i), undefined) + } + for (var i = 98; i < 100; i ++) { + t.equal(cache.get(i), i) + } + + // now remove the max restriction, and try again. + cache.max = "hello" + for (var i = 0; i < 100; i ++) cache.set(i, i) + t.equal(cache.length, 100) + for (var i = 0; i < 100; i ++) { + t.equal(cache.get(i), i) + } + // should trigger an immediate resize + cache.max = 3 + t.equal(cache.length, 3) + for (var i = 0; i < 97; i ++) { + t.equal(cache.get(i), undefined) + } + for (var i = 98; i < 100; i ++) { + t.equal(cache.get(i), i) + } + t.end() +}) + +test("reset", function (t) { + var cache = new LRU(10) + cache.set("a", "A") + cache.set("b", "B") + cache.reset() + t.equal(cache.length, 0) + t.equal(cache.max, 10) + t.equal(cache.get("a"), undefined) + t.equal(cache.get("b"), undefined) + t.end() +}) + + +// Note: `.dump()` is a debugging tool only. No guarantees are made +// about the format/layout of the response. +test("dump", function (t) { + var cache = new LRU(10) + var d = cache.dump(); + t.equal(Object.keys(d).length, 0, "nothing in dump for empty cache") + cache.set("a", "A") + var d = cache.dump() // { a: { key: "a", value: "A", lu: 0 } } + t.ok(d.a) + t.equal(d.a.key, "a") + t.equal(d.a.value, "A") + t.equal(d.a.lu, 0) + + cache.set("b", "B") + cache.get("b") + d = cache.dump() + t.ok(d.b) + t.equal(d.b.key, "b") + t.equal(d.b.value, "B") + t.equal(d.b.lu, 2) + + t.end() +}) + + +test("basic with weighed length", function (t) { + var cache = new LRU({ + max: 100, + length: function (item) { return item.size } + }) + cache.set("key", {val: "value", size: 50}) + t.equal(cache.get("key").val, "value") + t.equal(cache.get("nada"), undefined) + t.equal(cache.lengthCalculator(cache.get("key")), 50) + t.equal(cache.length, 50) + t.equal(cache.max, 100) + t.end() +}) + + +test("weighed length item too large", function (t) { + var cache = new LRU({ + max: 10, + length: function (item) { return item.size } + }) + t.equal(cache.max, 10) + + // should fall out immediately + cache.set("key", {val: "value", size: 50}) + + t.equal(cache.length, 0) + t.equal(cache.get("key"), undefined) + t.end() +}) + +test("least recently set with weighed length", function (t) { + var cache = new LRU({ + max:8, + length: function (item) { return item.length } + }) + cache.set("a", "A") + cache.set("b", "BB") + cache.set("c", "CCC") + cache.set("d", "DDDD") + t.equal(cache.get("d"), "DDDD") + t.equal(cache.get("c"), "CCC") + t.equal(cache.get("b"), undefined) + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("lru recently gotten with weighed length", function (t) { + var cache = new LRU({ + max: 8, + length: function (item) { return item.length } + }) + cache.set("a", "A") + cache.set("b", "BB") + cache.set("c", "CCC") + cache.get("a") + cache.get("b") + cache.set("d", "DDDD") + t.equal(cache.get("c"), undefined) + t.equal(cache.get("d"), "DDDD") + t.equal(cache.get("b"), "BB") + t.equal(cache.get("a"), "A") + t.end() +}) + +test("set returns proper booleans", function(t) { + var cache = new LRU({ + max: 5, + length: function (item) { return item.length } + }) + + t.equal(cache.set("a", "A"), true) + + // should return false for max exceeded + t.equal(cache.set("b", "donuts"), false) + + t.equal(cache.set("b", "B"), true) + t.equal(cache.set("c", "CCCC"), true) + t.end() +}) + +test("drop the old items", function(t) { + var cache = new LRU({ + max: 5, + maxAge: 50 + }) + + cache.set("a", "A") + + setTimeout(function () { + cache.set("b", "b") + t.equal(cache.get("a"), "A") + }, 25) + + setTimeout(function () { + cache.set("c", "C") + // timed out + t.notOk(cache.get("a")) + }, 60) + + setTimeout(function () { + t.notOk(cache.get("b")) + t.equal(cache.get("c"), "C") + }, 90) + + setTimeout(function () { + t.notOk(cache.get("c")) + t.end() + }, 155) +}) + +test("disposal function", function(t) { + var disposed = false + var cache = new LRU({ + max: 1, + dispose: function (k, n) { + disposed = n + } + }) + + cache.set(1, 1) + cache.set(2, 2) + t.equal(disposed, 1) + cache.set(3, 3) + t.equal(disposed, 2) + cache.reset() + t.equal(disposed, 3) + t.end() +}) + +test("disposal function on too big of item", function(t) { + var disposed = false + var cache = new LRU({ + max: 1, + length: function (k) { + return k.length + }, + dispose: function (k, n) { + disposed = n + } + }) + var obj = [ 1, 2 ] + + t.equal(disposed, false) + cache.set("obj", obj) + t.equal(disposed, obj) + t.end() +}) + +test("has()", function(t) { + var cache = new LRU({ + max: 1, + maxAge: 10 + }) + + cache.set('foo', 'bar') + t.equal(cache.has('foo'), true) + cache.set('blu', 'baz') + t.equal(cache.has('foo'), false) + t.equal(cache.has('blu'), true) + setTimeout(function() { + t.equal(cache.has('blu'), false) + t.end() + }, 15) +}) + +test("stale", function(t) { + var cache = new LRU({ + maxAge: 10, + stale: true + }) + + cache.set('foo', 'bar') + t.equal(cache.get('foo'), 'bar') + t.equal(cache.has('foo'), true) + setTimeout(function() { + t.equal(cache.has('foo'), false) + t.equal(cache.get('foo'), 'bar') + t.equal(cache.get('foo'), undefined) + t.end() + }, 15) +}) + +test("lru update via set", function(t) { + var cache = LRU({ max: 2 }); + + cache.set('foo', 1); + cache.set('bar', 2); + cache.del('bar'); + cache.set('baz', 3); + cache.set('qux', 4); + + t.equal(cache.get('foo'), undefined) + t.equal(cache.get('bar'), undefined) + t.equal(cache.get('baz'), 3) + t.equal(cache.get('qux'), 4) + t.end() +}) diff --git a/node_modules/karma/node_modules/useragent/node_modules/lru-cache/test/foreach.js b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/test/foreach.js new file mode 100644 index 00000000..eefb80d9 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/test/foreach.js @@ -0,0 +1,52 @@ +var test = require('tap').test +var LRU = require('../') + +test('forEach', function (t) { + var l = new LRU(5) + for (var i = 0; i < 10; i ++) { + l.set(i.toString(), i.toString(2)) + } + + var i = 9 + l.forEach(function (val, key, cache) { + t.equal(cache, l) + t.equal(key, i.toString()) + t.equal(val, i.toString(2)) + i -= 1 + }) + + // get in order of most recently used + l.get(6) + l.get(8) + + var order = [ 8, 6, 9, 7, 5 ] + var i = 0 + + l.forEach(function (val, key, cache) { + var j = order[i ++] + t.equal(cache, l) + t.equal(key, j.toString()) + t.equal(val, j.toString(2)) + }) + + t.end() +}) + +test('keys() and values()', function (t) { + var l = new LRU(5) + for (var i = 0; i < 10; i ++) { + l.set(i.toString(), i.toString(2)) + } + + t.similar(l.keys(), ['9', '8', '7', '6', '5']) + t.similar(l.values(), ['1001', '1000', '111', '110', '101']) + + // get in order of most recently used + l.get(6) + l.get(8) + + t.similar(l.keys(), ['8', '6', '9', '7', '5']) + t.similar(l.values(), ['1000', '110', '1001', '111', '101']) + + t.end() +}) diff --git a/node_modules/karma/node_modules/useragent/node_modules/lru-cache/test/memory-leak.js b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/test/memory-leak.js new file mode 100644 index 00000000..7af45b02 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/node_modules/lru-cache/test/memory-leak.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node --expose_gc + +var weak = require('weak'); +var test = require('tap').test +var LRU = require('../') +var l = new LRU({ max: 10 }) +var refs = 0 +function X() { + refs ++ + weak(this, deref) +} + +function deref() { + refs -- +} + +test('no leaks', function (t) { + // fill up the cache + for (var i = 0; i < 100; i++) { + l.set(i, new X); + // throw some gets in there, too. + if (i % 2 === 0) + l.get(i / 2) + } + + gc() + + var start = process.memoryUsage() + + // capture the memory + var startRefs = refs + + // do it again, but more + for (var i = 0; i < 10000; i++) { + l.set(i, new X); + // throw some gets in there, too. + if (i % 2 === 0) + l.get(i / 2) + } + + gc() + + var end = process.memoryUsage() + t.equal(refs, startRefs, 'no leaky refs') + + console.error('start: %j\n' + + 'end: %j', start, end); + t.pass(); + t.end(); +}) diff --git a/node_modules/karma/node_modules/useragent/package.json b/node_modules/karma/node_modules/useragent/package.json new file mode 100644 index 00000000..9bdd8ecf --- /dev/null +++ b/node_modules/karma/node_modules/useragent/package.json @@ -0,0 +1,69 @@ +{ + "name": "useragent", + "version": "2.0.7", + "description": "Fastest, most accurate & effecient user agent string parser, uses Browserscope's research for parsing", + "author": { + "name": "Arnout Kazemier" + }, + "main": "./index.js", + "keywords": [ + "agent", + "browser", + "browserscope", + "os", + "parse", + "parser", + "ua", + "ua-parse", + "ua-parser", + "user agent", + "user", + "user-agent", + "useragent", + "version" + ], + "maintainers": [ + { + "name": "Arnout Kazemier", + "email": "info@3rd-Eden.com", + "url": "http://www.3rd-Eden.com" + } + ], + "license": { + "type": "MIT", + "url": "https://github.com/3rd-Eden/useragent/blob/master/LICENSE" + }, + "repository": { + "type": "git", + "url": "http://github.com/3rd-Eden/useragent.git" + }, + "devDependencies": { + "should": "*", + "mocha": "*", + "long-stack-traces": "0.1.x", + "yamlparser": "0.0.x", + "request": "2.9.x", + "semver": "1.0.x", + "pre-commit": "0.0.x" + }, + "pre-commit": [ + "test", + "update" + ], + "scripts": { + "test": "mocha $(find test -name '*.test.js')", + "qa": "mocha --ui exports $(find test -name '*.qa.js')", + "update": "node ./bin/update.js" + }, + "dependencies": { + "lru-cache": "2.2.x" + }, + "readme": "# useragent - high performance user agent parser for Node.js\n\nUseragent originated as port of [browserscope.org][browserscope]'s user agent\nparser project also known as ua-parser. Useragent allows you to parse user agent\nstring with high accuracy by using hand tuned dedicated regular expressions for\nbrowser matching. This database is needed to ensure that every browser is\ncorrectly parsed as every browser vendor implements it's own user agent schema.\nThis is why regular user agent parsers have major issues because they will\nmost likely parse out the wrong browser name or confuse the render engine version\nwith the actual version of the browser.\n\n---\n\n### Build status [![BuildStatus](https://secure.travis-ci.org/3rd-Eden/useragent.png?branch=master)](http://travis-ci.org/3rd-Eden/useragent)\n\n---\n\n### High performance\n\nThe module has been developed with a benchmark driven approach. It has a\npre-compiled library that contains all the Regular Expressions and uses deferred\nor on demand parsing for Operating System and device information. All this\nengineering effort has been worth it as [this benchmark shows][benchmark]:\n\n```\nStarting the benchmark, parsing 62 useragent strings per run\n\nExecuted benchmark against node module: \"useragent\"\nCount (61), Cycles (5), Elapsed (5.559), Hz (1141.3739447904327)\n\nExecuted benchmark against node module: \"useragent_parser\"\nCount (29), Cycles (3), Elapsed (5.448), Hz (545.6817291171243)\n\nExecuted benchmark against node module: \"useragent-parser\"\nCount (16), Cycles (4), Elapsed (5.48), Hz (304.5373431830105)\n\nExecuted benchmark against node module: \"ua-parser\"\nCount (54), Cycles (3), Elapsed (5.512), Hz (1018.7561434659247)\n\nModule: \"useragent\" is the user agent fastest parser.\n```\n\n---\n\n### Installation\n\nInstallation is done using the Node Package Manager (NPM). If you don't have\nNPM installed on your system you can download it from\n[npmjs.org][npm]\n\n```\nnpm install useragent --save\n```\n\nThe `--save` flag tells NPM to automatically add it to your `package.json` file.\n\n---\n\n### API\n\n\nInclude the `useragent` parser in you node.js application:\n\n```js\nvar useragent = require('useragent');\n```\n\nThe `useragent` library allows you do use the automatically installed RegExp\nlibrary or you can fetch it live from the remote servers. So if you are\nparanoid and always want your RegExp library to be up to date to match with\nagent the widest range of `useragent` strings you can do:\n\n```js\nvar useragent = require('useragent');\nuseragent(true);\n```\n\nThis will async load the database from the server and compile it to a proper\nJavaScript supported format. If it fails to compile or load it from the remote\nlocation it will just fall back silently to the shipped version. If you want to\nuse this feature you need to add `yamlparser` and `request` to your package.json\n\n```\nnpm install yamlparser --save\nnpm install request --save\n```\n\n#### useragent.parse(useragent string[, js useragent]);\n\nThis is the actual user agent parser, this is where all the magic is happening.\nThe function accepts 2 arguments, both should be a `string`. The first argument\nshould the user agent string that is known on the server from the\n`req.headers.useragent` header. The other argument is optional and should be\nthe user agent string that you see in the browser, this can be send from the\nbrowser using a xhr request or something like this. This allows you detect if\nthe user is browsing the web using the `Chrome Frame` extension.\n\nThe parser returns a Agent instance, this allows you to output user agent\ninformation in different predefined formats. See the Agent section for more\ninformation.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\n\n// example for parsing both the useragent header and a optional js useragent\nvar agent2 = useragent.parse(req.headers['user-agent'], req.query.jsuseragent);\n```\n\nThe parse method returns a `Agent` instance which contains all details about the\nuser agent. See the Agent section of the API documentation for the available\nmethods.\n\n#### useragent.lookup(useragent string[, js useragent]);\n\nThis provides the same functionality as above, but it caches the user agent\nstring and it's parsed result in memory to provide faster lookups in the\nfuture. This can be handy if you expect to parse a lot of user agent strings.\n\nIt uses the same arguments as the `useragent.parse` method and returns exactly\nthe same result, but it's just cached.\n\n```js\nvar agent = useragent.lookup(req.headers['user-agent']);\n```\n\nAnd this is a serious performance improvement as shown in this benchmark:\n\n```\nExecuted benchmark against method: \"useragent.parse\"\nCount (49), Cycles (3), Elapsed (5.534), Hz (947.6844321931629)\n\nExecuted benchmark against method: \"useragent.lookup\"\nCount (11758), Cycles (3), Elapsed (5.395), Hz (229352.03831239208)\n```\n\n#### useragent.fromJSON(obj);\n\nTransforms the JSON representation of a `Agent` instance back in to a working\n`Agent` instance\n\n```js\nvar agent = useragent.parse(req.headers['user-agent'])\n , another = useragent.fromJSON(JSON.stringify(agent));\n\nconsole.log(agent == another);\n```\n\n#### useragent.is(useragent string).browsername;\n\nThis api provides you with a quick and dirty browser lookup. The underlying\ncode is usually found on client side scripts so it's not the same quality as\nour `useragent.parse` method but it might be needed for legacy reasons.\n\n`useragent.is` returns a object with potential matched browser names\n\n```js\nuseragent.is(req.headers['user-agent']).firefox // true\nuseragent.is(req.headers['user-agent']).safari // false\nvar ua = useragent.is(req.headers['user-agent'])\n\n// the object\n{\n version: '3'\n webkit: false\n opera: false\n ie: false\n chrome: false\n safari: false\n mobile_safari: false\n firefox: true\n}\n```\n\n---\n\n### Agents, OperatingSystem and Device instances\n\nMost of the methods mentioned above return a Agent instance. The Agent exposes\nthe parsed out information from the user agent strings. This allows us to\nextend the agent with more methods that do not necessarily need to be in the\ncore agent instance, allowing us to expose a plugin interface for third party\ndevelopers and at the same time create a uniform interface for all versioning.\n\nThe Agent has the following property\n\n- `family` The browser family, or browser name, it defaults to Other.\n- `major` The major version number of the family, it defaults to 0.\n- `minor` The minor version number of the family, it defaults to 0.\n- `patch` The patch version number of the family, it defaults to 0.\n\nIn addition to the properties mentioned above, it also has 2 special properties,\nwhich are:\n\n- `os` OperatingSystem instance\n- `device` Device instance\n\nWhen you access those 2 properties the agent will do on demand parsing of the\nOperating System or/and Device information.\n\nThe OperatingSystem has the same properties as the Agent, for the Device we\ndon't have any versioning information available, so only the `family` property is\nset there. If we cannot find the family, they will default to `Other`.\n\nThe following methods are available:\n\n#### Agent.toAgent();\n\nReturns the family and version number concatinated in a nice human readable\nstring.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.toAgent(); // 'Chrome 15.0.874'\n```\n\n#### Agent.toString();\n\nReturns the results of the `Agent.toAgent()` but also adds the parsed operating\nsystem to the string in a human readable format.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.toString(); // 'Chrome 15.0.874 / Mac OS X 10.8.1'\n\n// as it's a to string method you can also concat it with another string\n'your useragent is ' + agent;\n// 'your useragent is Chrome 15.0.874 / Mac OS X 10.8.1'\n```\n#### Agent.toVersion();\n\nReturns the version of the browser in a human readable string.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.toVersion(); // '15.0.874'\n```\n\n#### Agent.toJSON();\n\nGenerates a JSON representation of the Agent. By using the `toJSON` method we\nautomatically allow it to be stringified when supplying as to the\n`JSON.stringify` method.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.toJSON(); // returns an object\n\nJSON.stringify(agent);\n```\n\n#### OperatingSystem.toString();\n\nGenerates a stringified version of operating system;\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.os.toString(); // 'Mac OSX 10.8.1'\n```\n\n#### OperatingSystem.toVersion();\n\nGenerates a stringified version of operating system's version;\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.os.toVersion(); // '10.8.1'\n```\n\n#### OperatingSystem.toJSON();\n\nGenerates a JSON representation of the OperatingSystem. By using the `toJSON`\nmethod we automatically allow it to be stringified when supplying as to the\n`JSON.stringify` method.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.os.toJSON(); // returns an object\n\nJSON.stringify(agent.os);\n```\n\n#### Device.toString();\n\nGenerates a stringified version of device;\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.device.toString(); // 'Asus A100'\n```\n\n#### Device.toVersion();\n\nGenerates a stringified version of device's version;\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.device.toVersion(); // '' , no version found but could also be '0.0.0'\n```\n\n#### Device.toJSON();\n\nGenerates a JSON representation of the Device. By using the `toJSON` method we\nautomatically allow it to be stringified when supplying as to the\n`JSON.stringify` method.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.device.toJSON(); // returns an object\n\nJSON.stringify(agent.device);\n```\n\n### Adding more features to the useragent\n\nAs I wanted to keep the core of the user agent parser as clean and fast as\npossible I decided to move some of the initially planned features to a new\n`plugin` file.\n\nThese extensions to the Agent prototype can be loaded by requiring the\n`useragent/features` file:\n\n```js\nvar useragent = require('useragent');\nrequire('useragent/features');\n```\n\nThe initial release introduces 1 new method, satisfies, which allows you to see\nif the version number of the browser satisfies a certain range. It uses the\nsemver library to do all the range calculations but here is a small summary of\nthe supported range styles:\n\n* `>1.2.3` Greater than a specific version.\n* `<1.2.3` Less than.\n* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`.\n* `~1.2.3` := `>=1.2.3 <1.3.0`.\n* `~1.2` := `>=1.2.0 <2.0.0`.\n* `~1` := `>=1.0.0 <2.0.0`.\n* `1.2.x` := `>=1.2.0 <1.3.0`.\n* `1.x` := `>=1.0.0 <2.0.0`.\n\nAs it requires the `semver` module to function you need to install it\nseperately:\n\n```\nnpm install semver --save\n```\n\n#### Agent.satisfies('range style here');\n\nCheck if the agent matches the supplied range.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.satisfies('15.x || >=19.5.0 || 25.0.0 - 17.2.3'); // true\nagent.satisfies('>16.12.0'); // false\n```\n---\n\n### Migrations\n\nFor small changes between version please review the [changelog][changelog].\n\n#### Upgrading from 1.10 to 2.0.0\n\n- `useragent.fromAgent` has been removed.\n- `agent.toJSON` now returns an Object, use `JSON.stringify(agent)` for the old\n behaviour.\n- `agent.os` is now an `OperatingSystem` instance with version numbers. If you\n still a string only representation do `agent.os.toString()`.\n- `semver` has been removed from the dependencies, so if you are using the\n `require('useragent/features')` you need to add it to your own dependencies\n\n#### Upgrading from 0.1.2 to 1.0.0\n\n- `useragent.browser(ua)` has been renamed to `useragent.is(ua)`.\n- `useragent.parser(ua, jsua)` has been renamed to `useragent.parse(ua, jsua)`.\n- `result.pretty()` has been renamed to `result.toAgent()`.\n- `result.V1` has been renamed to `result.major`.\n- `result.V2` has been renamed to `result.minor`.\n- `result.V3` has been renamed to `result.patch`.\n- `result.prettyOS()` has been removed.\n- `result.match` has been removed.\n\n---\n\n### License\n\nMIT\n\n[browserscope]: http://www.browserscope.org/\n[benchmark]: /3rd-Eden/useragent/blob/master/benchmark/run.js\n[changelog]: /3rd-Eden/useragent/blob/master/CHANGELOG.md\n[npm]: http://npmjs.org\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/3rd-Eden/useragent/issues" + }, + "homepage": "https://github.com/3rd-Eden/useragent", + "_id": "useragent@2.0.7", + "_from": "useragent@~2.0.4" +} diff --git a/node_modules/karma/node_modules/useragent/static/user_agent.after.yaml b/node_modules/karma/node_modules/useragent/static/user_agent.after.yaml new file mode 100644 index 00000000..66b0b0b7 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/static/user_agent.after.yaml @@ -0,0 +1,14 @@ +user_agent_parsers: + # browsers + - regex: '(Thunderbird)/(\d+)\.(\d+)\.?(\d+)?' + + # command line tools + - regex: '(Wget)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)' + + - regex: '(curl)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'cURL' + +os_parsers: + - regex: '(Red Hat)' + +device_parsers: diff --git a/node_modules/karma/node_modules/useragent/test/features.test.js b/node_modules/karma/node_modules/useragent/test/features.test.js new file mode 100644 index 00000000..a6c3ee3a --- /dev/null +++ b/node_modules/karma/node_modules/useragent/test/features.test.js @@ -0,0 +1,16 @@ +describe('useragent/features', function () { + 'use strict'; + + var useragent = require('../') + , features = require('../features') + , ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.24 Safari/535.2"; + + describe('#satisfies', function () { + it('should satisfy that range selector', function () { + var agent = useragent.parse(ua); + + agent.satisfies('15.x || >=19.5.0 || 25.0.0 - 17.2.3').should.be_true; + agent.satisfies('>16.12.0').should.be_false; + }); + }); +}); diff --git a/node_modules/karma/node_modules/useragent/test/fixtures/firefoxes.yaml b/node_modules/karma/node_modules/useragent/test/fixtures/firefoxes.yaml new file mode 100644 index 00000000..8c0d50b7 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/test/fixtures/firefoxes.yaml @@ -0,0 +1,1386 @@ +# http://people.mozilla.com/~dwitte/ua.txt +# +# The following are some example User Agent strings for various versions of +# Firefox and other Gecko-based browsers. Many of these have been modified by +# extensions, external applications, distributions, and users. The version number +# for Firefox 5.0 (and the corresponding Gecko version) is tentative. See +# https://developer.mozilla.org/En/Gecko_User_Agent_String_Reference for more +# details. Credit to http://useragentstring.com/ for providing some of these +# strings. + +test_cases: + # Firefox 4.0 (prerelease) + - user_agent_string: Mozilla/5.0 (Windows NT 6.0; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + + # Firefox 4.0.1 + - user_agent_string: Mozilla/5.0 (Windows NT 5.2; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (WindowsCE 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + + # Firefox 4.0 (prerelease) + - user_agent_string: Mozilla/5.0 (Windows NT 6.0; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + + # Firefox 5.0 (version number tentative -- not yet released) + - user_agent_string: Mozilla/5.0 (Windows NT 5.2; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (WindowsCE 6.0; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux x86_64; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + + # Firefox 3.6 + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100804 Gentoo Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100723 SUSE/3.6.8-0.1.1 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.2.8) Gecko/20100722 Ubuntu/10.04 (lucid) Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.8) Gecko/20100727 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.9.2.8) Gecko/20100725 Gentoo Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; FreeBSD i386; de-CH; rv:1.9.2.8) Gecko/20100729 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-BR; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; he; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0C) + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.3) Gecko/20121221 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.8) Gecko/20100722 BTRS86393 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0C) + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-TW; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E) + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; ro; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en; rv:1.9.2.8) Gecko/20100805 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.7) Gecko/20100723 Fedora/3.6.7-1.fc13 Firefox/3.6.7 + family: 'Firefox' + major: '3' + minor: '6' + patch: '7' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.7) Gecko/20100726 CentOS/3.6-3.el5.centos Firefox/3.6.7 + family: 'Firefox' + major: '3' + minor: '6' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; hu; rv:1.9.2.7) Gecko/20100713 Firefox/3.6.7 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.9.2.7) Gecko/20100713 Firefox/3.6.7 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '7' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 GTB7.0 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-PT; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-CN; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729; .NET4.0E) + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.4) Gecko/20100614 Ubuntu/10.04 (lucid) Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.4) Gecko/20100625 Gentoo Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; cs; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-CN; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100527 Firefox/3.6.4 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100527 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 GTB7.0 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.4) Gecko/20100503 Firefox/3.6.4 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; ko; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; cs; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 GTB7.0 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.2.3) Gecko/20100403 Fedora/3.6.3-4.fc13 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.3) Gecko/20100401 SUSE/3.6.3-1.1 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; ko-KR; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100404 Ubuntu/10.04 (lucid) Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.0 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-GB; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; nl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; fr; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; hu; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.0 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; cs; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; ca; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; sv-SE; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.7; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 + family: 'Firefox' + major: '3' + minor: '6' + patch: '2' + + # Firefox 3.5 + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.9) Gecko/20100402 Ubuntu/9.10 (karmic) Firefox/3.5.9 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.9) Gecko/20100330 Fedora/3.5.9-2.fc12 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.9) Gecko/20100317 SUSE/3.5.9-0.1.1 Firefox/3.5.9 GTB7.0 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; es-CL; rv:1.9.1.9) Gecko/20100402 Ubuntu/9.10 (karmic) Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.1.9) Gecko/20100317 SUSE/3.5.9-0.1.1 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.9.1.9) Gecko/20100330 Fedora/3.5.9-1.fc12 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.9) Gecko/20100317 SUSE/3.5.9-0.1 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9 GTB7.1 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100315 Ubuntu/9.10 (karmic) Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.4) Gecko/20091028 Ubuntu/9.10 (karmic) Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; tr; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB7.1 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; hu; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; et; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; es-ES; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB5 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB7.0 (.NET CLR 3.0.30618) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; ca; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB7.0 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc11 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8) Gecko/20100318 Gentoo Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; FreeBSD i386; ja-JP; rv:1.9.1.8) Gecko/20100305 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; sl; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 (.NET CLR 3.5.30729) FirePHP/0.4 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 GTB6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 GTB7.0 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2) Gecko/20100305 Gentoo Firefox/3.5.7 + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.1.7) Gecko/20100106 Ubuntu/9.10 (karmic) Firefox/3.5.7 + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.7) Gecko/20091222 SUSE/3.5.7-1.1.1 Firefox/3.5.7 + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; fr; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 3.0.04506.648) + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; fa; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 MRA 5.5 (build 02842) Firefox/3.5.7 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.6) Gecko/20100117 Gentoo Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.6) Gecko/20091216 Fedora/3.5.6-1.fc11 Firefox/3.5.6 GTB6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.6) Gecko/20091201 SUSE/3.5.6-1.1.1 Firefox/3.5.6 GTB6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.6) Gecko/20100118 Gentoo Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 GTB6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 GTB7.0 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.6) Gecko/20091201 SUSE/3.5.6-1.1.1 Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.9.1.6) Gecko/20100107 Fedora/3.5.6-1.fc12 Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; ca; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; id; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.6) Gecko/20091201 MRA 5.4 (build 02647) Firefox/3.5.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 MRA 5.5 (build 02842) Firefox/3.5.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 MRA 5.5 (build 02842) Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 GTB6 (.NET CLR 3.5.30729) FBSMTWB + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729) FBSMTWB + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; sv-SE; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 + family: 'Firefox' + major: '3' + minor: '5' + patch: '3' + + # Firefox on the next Gecko major release (preliminary) + - user_agent_string: Mozilla/5.0 (Windows NT 5.2; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (WindowsCE 6.0; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + +# # Fennec 2.0.1 (not yet released) +# - user_agent_string: Mozilla/5.0 (Android; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1 +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (Maemo; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1 +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1 +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1 +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1 +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: '1' +# +# # Fennec 2.0 (prerelease) +# - user_agent_string: Mozilla/5.0 (Android; Linux armv7l; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre Fennec/2.0b1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' +# - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre Fennec/2.0b1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' +# - user_agent_string: Mozilla/5.0 (Windows NT 5.1; rv:2.0b6pre) Gecko/20100902 Firefox/4.0b6pre Fennec/2.0b1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' +# - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0b4pre) Gecko/20100818 Firefox/4.0b4pre Fennec/2.0a1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' +# - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0b4pre) Gecko/20100812 Firefox/4.0b4pre Fennec/2.0a1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' +# - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0b3pre) Gecko/20100730 Firefox/4.0b3pre Fennec/2.0a1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' + + # Camino 2.2 (not yet released) + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.4; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Camino/2.2.1 + family: 'Camino' + major: '2' + minor: '2' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Camino/2.2.1 + family: 'Camino' + major: '2' + minor: '2' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Camino/2.2.1 + family: 'Camino' + major: '2' + minor: '2' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; PPC Mac OS X 10.4; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Camino/2.2.1 + family: 'Camino' + major: '2' + minor: '2' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; PPC Mac OS X 10.5; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Camino/2.2.1 + family: 'Camino' + major: '2' + minor: '2' + patch: '1' + + # Camino 2.0 + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en; rv:1.9.0.19) Gecko/2010051911 Camino/2.0.3 (like Firefox/3.0.19) + family: 'Camino' + major: '2' + minor: '0' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; nl; rv:1.9.0.19) Gecko/2010051911 Camino/2.0.3 (MultiLang) (like Firefox/3.0.19) + family: 'Camino' + major: '2' + minor: '0' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en; rv:1.9.0.18) Gecko/2010021619 Camino/2.0.2 (like Firefox/3.0.18) + family: 'Camino' + major: '2' + minor: '0' + patch: '2' + + # Camino 1.6 + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; it; rv:1.8.1.21) Gecko/20090327 Camino/1.6.7 (MultiLang) (like Firefox/2.0.0.21pre) + family: 'Camino' + major: '1' + minor: '6' + patch: '7' + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.21) Gecko/20090327 Camino/1.6.7 (like Firefox/2.0.0.21pre) + family: 'Camino' + major: '1' + minor: '6' + patch: '7' + + # Camino 1.5 + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.12) Gecko/20080206 Camino/1.5.5 + family: 'Camino' + major: '1' + minor: '5' + patch: '5' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X Mach-O; en; rv:1.8.1.12) Gecko/20080206 Camino/1.5.5 + family: 'Camino' + major: '1' + minor: '5' + patch: '5' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.11) Gecko/20071128 Camino/1.5.4 + family: 'Camino' + major: '1' + minor: '5' + patch: '4' + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.6) Gecko/20070809 Camino/1.5.1 + family: 'Camino' + major: '1' + minor: '5' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.6) Gecko/20070809 Camino/1.5.1 + family: 'Camino' + major: '1' + minor: '5' + patch: '1' +# +# # Thunderbird 3.1 +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; sv-SE; rv:1.9.2.8) Gecko/20100802 Thunderbird/3.1.2 ThunderBrowse/3.3.2 +# family: 'Thunderbird' +# major: '3' +# minor: '1' +# patch: '2' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.2.8) Gecko/20100802 Thunderbird/3.1.2 +# family: 'Thunderbird' +# major: '3' +# minor: '1' +# patch: '2' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.7) Gecko/20100713 Lightning/1.0b2 Thunderbird/3.1.1 ThunderBrowse/3.3.1 +# family: 'Thunderbird' +# major: '3' +# minor: '1' +# patch: '1' +# +# # Thunderbird 3.0 +# - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.10) Gecko/20100621 Fedora/3.0.5-1.fc13 Lightning/1.0b2pre Thunderbird/3.0.5 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '5' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1.10) Gecko/20100512 Lightning/1.0b1 Thunderbird/3.0.5 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '5' +# - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100423 Thunderbird/3.0.4 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '4' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1.9) Gecko/20100317 Lightning/1.0b1 Thunderbird/3.0.4 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '4' +# - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.9) Gecko/20100317 Thunderbird/3.0.4 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '4' +# - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; pl; rv:1.9.1.9) Gecko/20100317 Thunderbird/3.0.4 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '4' +# - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.9) Gecko/20100317 Thunderbird/3.0.4 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '4' +# - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8) Gecko/20100408 Thunderbird/3.0.3 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '3' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.9.1.7) Gecko/20100111 Thunderbird/3.0.1 ThunderBrowse/3.2.8.1 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-CA; rv:1.9.1.7) Gecko/20100111 Thunderbird/3.0.1 ThunderBrowse/3.2.8.1 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.9.1.7) Gecko/20100111 Thunderbird/3.0.1 ThunderBrowse/3.2.8.1 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '1' + + # SeaMonkey 2.1.1 (not yet released) + - user_agent_string: Mozilla/5.0 (Windows NT 5.2; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (WindowsCE 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + + # SeaMonkey 2.1 (prerelease) + - user_agent_string: Mozilla/5.0 (Windows; Windows NT 5.2; rv:2.0b3pre) Gecko/20100803 SeaMonkey/2.1a3pre + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: 'a3pre' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.3a4pre) Gecko/20100404 SeaMonkey/2.1a1pre + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: 'a1pre' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.3a3pre) Gecko/20100312 SeaMonkey/2.1a1pre + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: 'a1pre' + + # SeaMonkey 2.0 + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100721 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100714 SUSE/2.0.6-2.1 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux ia64; de; rv:1.9.1.11) Gecko/20100820 Lightning/1.0b2pre SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.11) Gecko/20100722 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 9.0; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11) Gecko/20100722 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100630 SeaMonkey/2.0.6pre + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6pre' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100629 SeaMonkey/2.0.6pre + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6pre' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11pre) Gecko/20100515 SeaMonkey/2.0.6pre + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6pre' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11pre) Gecko/20100508 SeaMonkey/2.0.6pre + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6pre' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.10) Gecko/20100504 Lightning/1.0b1 Mnenhy/0.8.2 SeaMonkey/2.0.5 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '5' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.1.10) Gecko/20100504 Lightning/1.0b1 SeaMonkey/2.0.5 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '5' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.10) Gecko/20100504 Lightning/1.0b1 SeaMonkey/2.0.5 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '5' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.9) Gecko/20100428 Lightning/1.0b1 SeaMonkey/2.0.4 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '4' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100317 SUSE/2.0.4-3.2 Lightning/1.0b1 SeaMonkey/2.0.4 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.9) Gecko/20100317 Lightning/1.0b1 SeaMonkey/2.0.4 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.8) Gecko/20100205 SeaMonkey/2.0.3 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.7) Gecko/20100104 SeaMonkey/2.0.2 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '2' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20100104 SeaMonkey/2.0.2 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '2' diff --git a/node_modules/karma/node_modules/useragent/test/fixtures/pgts.yaml b/node_modules/karma/node_modules/useragent/test/fixtures/pgts.yaml new file mode 100644 index 00000000..2210b824 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/test/fixtures/pgts.yaml @@ -0,0 +1,62356 @@ +test_cases: + - user_agent_string: "abot/0.1 (abot; http://www.abot.com; abot@abot.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Ace Explorer" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ACS-NF/3.0 NEC-c616/001.00" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ACS-NF/3.0 NEC-e616/001.01 (www.proxomitron.de)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ActiveBookmark 1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; AI)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AIM" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AIM/30 (Mozilla 1.24b; Windows; I; 32-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "aipbot/1.0 (aipbot; http://www.aipbot.com; aipbot@aipbot.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Alizee iPod 2005 (Beta; Mac OS X)" + family: "Mobile Safari" + major: + minor: + patch: + - user_agent_string: "alpha 06" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.5 (compatible; alpha/06; AmigaOS 1337)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ALPHA/06_(Win98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "amaya/8.3 libwww/5.4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaOS AmigaVoyager" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx (AmigaVoyager/2.95; AmigaOS/MC680x0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Voyager; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.6 (compatible; AmigaVoyager; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaVoyager/2.95 (compatible; MC680x0; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; AmigaVoyager/2.95; AmigaOS/MC680x0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaVoyager/3.3.122 (AmigaOS/PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaVoyager/3.4.4 (MorphOS/PPC native)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Amiga Voyager" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; AnsearchBot/1.0; +http://www.ansearch.com.au/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ANTFresco 1.20; RISC OS 3.11)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04 (compatible; ANTFresco/2.13; RISC OS 4.02)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04 (compatible; NCBrowser/2.35 (1.45.2.1); ANTFresco/2.17; RISC OS-NC 5.13 Laz1UK1802)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ANTFresco 2.20; RISC OS 3.11)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AOLserver-Tcl/3.5.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AOL 8.0 (compatible; AOL 8.0; DOS; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AOL/8.0 (Lindows 2003)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "aolbrowser/1.1 InterCon-Web-Library/1.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ArachnetAgent 2.3/4.78 (TuringOS; Turing Machine; 0.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx ( ; ; AmigaOS 3.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx (AmigaVoyager/2.95; AmigaOS/MC680x0; Mod-X by Pe)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx (compatible; AmigaVoyager/2.95; AmigaOS" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx (compatible; AmigaVoyager/2.95; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ARexx (compatible; ARexx; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx (compatible; MSIE 6.0; AmigaOS5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Arexx (compatible; MSIE 6.0; AmigaOS5.0) IBrowse 4.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ARexx; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ARexx; AmigaOS; Avant Browser [avantbrowser.com]; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; arexx)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "ArtfaceBot (compatible; MSIE 6.0; Mozilla/4.0; Windows NT 5.1;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; Ask Jeeves/Teoma; +http://sp.ask.com/docs/about/tech_crawling.html)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Astra/1.0 (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Astra/2.0 (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Atari/2600b (compatible; 2port; Wood Grain)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Atari/2600 (GalaxianOS; U; en-US) cartridge/$29.95" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Auto-Proxy Downloader" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Advanced Browser (http://www.avantbrowser.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Avant Browser (http://www.avantbrowser.com)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Avant Browser [avantbrowser.com])" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com])" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com])" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Avant Browser/1.2.789rel1 (http://www.avantbrowser.com)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Avantgo 5.5" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; AvantGo 5.2; FreeBSD)" + family: "AvantGo" + major: '5' + minor: '2' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; AvantGo 6.0; FreeBSD)" + family: "AvantGo" + major: '6' + minor: '0' + patch: + - user_agent_string: "Amiga" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaOS" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Amiga OS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Aweb/2.3 (AmigaOS 3.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Amiga-AWeb/3.4APL" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; AWEB 3.4 SE; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Amiga-AWeb/3.4.167SE" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Amiga-AWeb/3.5.05 beta" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; BecomeBot/2.2.1; MSIE 6.0 compatible; +http://www.become.com/webmasters.html)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "BlackBerry7730/3.7.1 UP.Link/5.1.2.5" + family: "Blackberry" + major: '7730' + minor: + patch: + - user_agent_string: "UPG1 UP/4.0 (compatible; Blazer 1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Bobby/3.3 RPT-HTTPClient/0.3-3E" + family: "Other" + major: + minor: + patch: + - user_agent_string: "boitho.com-dc/0.70 ( http://www.boitho.com/dcbot.html )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "boitho.com-dc/0.71 ( http://www.boitho.com/dcbot.html )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "$BotName/$BotVersion [en] (UNIX; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Brain/1.0 [de] (Human RAW 1.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Browsers Part 4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Buscaplus Robi/1.0 (http://www.buscaplus.com/robi/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "BuyGet/1.0 Agent-Admin/webmaster@kfda.go.kr" + family: "Other" + major: + minor: + patch: + - user_agent_string: "CacheBot/0.445 (compatible, http://www.cachebot.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "CDM-8900" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Cerberian Drtrs Version-3.2-Build-1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.0; Update a; AK; Windows 95) via proxy gateway CERN-HTTPD/3.0 libwww/2.17" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "cfetch/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "CFNetwork/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP900/R101 Profile/MIDP-2.0 Configuration/CLDC-1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP900/R102 Profile/MIDP-2.0 Configuration/CLDC-1.0 Rev/MR4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP910i/R3A SEMC-Browser/Symbian/3.0 Profile/MIDP-2.0 Configuration/CLDC-1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT610/R101 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT610/R201 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT610/R201 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/5.1.2.1 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT610/R401 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT610/R401 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/5.1.1.3 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonZ600/R401 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonK700i/R2AA SEMC-Browser/4.0.2 Profile/MIDP-2.0 Configuration/CLDC-1.1 (Google WAP Proxy/1.0)" + family: "SEMC-Browser" + major: '4' + minor: '0' + patch: + - user_agent_string: "SonyEricssonK700i/R2AE SEMC-Browser/4.0.3 Profile/MIDP-2.0 Configuration/CLDC-1.1 UP.Link/6.2.3.15.0 (Google WAP Proxy/1.0)" + family: "SEMC-Browser" + major: '4' + minor: '0' + patch: + - user_agent_string: "Clushbot/3.31-BinaryFury (+http://www.clush.com/bot.html)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 1.0; Commodore64)" + family: "IE" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 2.0; Commodore64)" + family: "IE" + major: '2' + minor: '0' + patch: + - user_agent_string: "Contiki/1.0 (Commodore 64; http://dunkels.com/adam/contiki/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ConveraMultiMediaCrawler/0.1 (+http://www.authoritativeweb.com/crawl)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "CosmixCrawler/0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "crawler (ISSpider-3.0; http://www.yoururlgoeshere.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Crawler0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.0 (compatible; Crazy Browser 1.0.1; FreeBSD 3.2-RELEASE i386)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FREE; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MyIE2; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; APCMAG; NetCaptor 6.5.0B7; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; 3305; Versatel.de ISDN 0404; Crazy Browser 1.0.5; onlineTV; www.cdesign.de)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; Crazy Browser 1.0.5; Tyco Electronics 01/2003)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {4CBEAFB3-10C9-497A-B016-7FEBFBD707E9}; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; brip1; RainBird 1.01/HT; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Crazy Browser 1.0.5; FDM)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Crazy Browser 1.0.5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Crazy Browser 1.0.5; iRider 2.20.0018)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusNetDSL6; Crazy Browser 1.0.5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Crazy Browser 1.0.5; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A5020528-0A08-4436-8CD1-D02C46132E5A}; SV1; Crazy Browser 1.0.5; CustomExchangeBrowser; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=vBB1c.00; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; Alexa Toolbar)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; (R1 1.1); .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; (R1 1.5))" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; SV1; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; FunWebProducts; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GoogleBot; Crazy Browser 1.0.5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Katiesoft 7; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Crazy Browser 1.0.5; Alexa Toolbar)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Socantel; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.1.4322; FDM)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Texas Instruments; MyIE2; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Crazy Browser 1.0.5; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Crazy Browser 2.0.0 Beta 1)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; YPC 3.0.1; yie6; Crazy Browser 2.0.0 Beta 1)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 2.0.0 Beta 1)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 2.0.0 Beta 1; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 2.0.0 Beta 1)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 2.0.0 Beta 1; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 2.0.0 Beta 1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 2.0.0 Beta 1; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyTotalSearch; Maxthon; Crazy Browser 2.0.0 Beta 1)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; Deepnet Explorer 1.3.2; Crazy Browser 2.0.0 Beta 1; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "curl/7.10.2 (powerpc-apple-darwin7.0) libcurl/7.10.2 OpenSSL/0.9.7b zlib/1.1.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.10.6 (i386-redhat-linux-gnu) libcurl/7.10.6 OpenSSL/0.9.7a ipv6 zlib/1.1.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.10.6 (i386-redhat-linux-gnu) libcurl/7.10.6 OpenSSL/0.9.7a ipv6 zlib/1.2.0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.11.2 (i686-pc-linux-gnu) libcurl/7.10.2 OpenSSL/0.9.6i ipv6 zlib/1.1.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.12.0 (i686-pc-linux-gnu) libcurl/7.12.0 OpenSSL/0.9.7e ipv6 zlib/1.2.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.7.2 (powerpc-apple-darwin6.0) libcurl 7.7.2 (OpenSSL 0.9.6b)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.7.3 (i686-pc-linux-gnu) libcurl 7.7.3 (OpenSSL 0.9.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.7.3 (win32) libcurl 7.7.3 (OpenSSL 0.9.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.9.3 (powerpc-ibm-aix4.3.3.0) libcurl 7.9.3 (OpenSSL 0.9.6m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.9.5 (i386-redhat-linux-gnu) libcurl 7.9.5 (OpenSSL 0.9.6b) (ipv6 enabled)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.9.8 (i386-redhat-linux-gnu) libcurl 7.9.8 (OpenSSL 0.9.7a) (ipv6 enabled)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DA 5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DA 5.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "daemon (AmigaOS; alpha/06; AmigaOS mod-x)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DataFountains/DMOZ Downloader" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; DB Browse 4.3; DB OS 6.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "deepak-USC/ISI" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Deepnet Explorer" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Deepnet Explorer 1.0.1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Dillo/0.6.4" + family: "Dillo" + major: '0' + minor: '6' + patch: '4' + - user_agent_string: "Dillo/0.7.3" + family: "Dillo" + major: '0' + minor: '7' + patch: '3' + - user_agent_string: "Dillo/0.8.0" + family: "Dillo" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Dillo/0.8.0-pre" + family: "Dillo" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Dillo/0.8.1" + family: "Dillo" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Dillo/0.8.2" + family: "Dillo" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Dillo/0.8.2-pre" + family: "Dillo" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Dillo/0.8.3" + family: "Dillo" + major: '0' + minor: '8' + patch: '3' + - user_agent_string: "Dillo/0.8.3-rc2" + family: "Dillo" + major: '0' + minor: '8' + patch: '3' + - user_agent_string: "Dillo/0.8.4" + family: "Dillo" + major: '0' + minor: '8' + patch: '4' + - user_agent_string: "Dillo/0.8.5-pre" + family: "Dillo" + major: '0' + minor: '8' + patch: '5' + - user_agent_string: "Dillo/27951.4" + family: "Dillo" + major: '27951' + minor: '4' + patch: + - user_agent_string: "dloader(NaverRobot)/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; DLW 2.0; Win32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DoCoMo/1.0/D503iS/c10" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DoCoMo/1.0/P502i/c10 (Google CHTML Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DoCoMo/2.0 F900i(c100;TB;W22H12),gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DoCoMo/2.0 N900i(c100;TB;W24H12)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Doris/1.10 [en] (Symbian)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Doris/1.17 [en] (Symbian)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Download.exe(1.1) (+http://www.sql-und-xml.de/freeware-tools/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Download Master" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Download Ninja 7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "EasyDL/3.04 http://keywen.com/Encyclopedia/Bot" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks (0.10rc1; Linux 2.6.9-gentoo-r10 i686; 80x25)" + family: "Links" + major: '0' + minor: '10' + patch: + - user_agent_string: "ELinks (0.4.2; cygwin; 700)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4.2; Linux; )" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre18; Linux 2.2.22 i686; 80x25)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre5; Linux 2.2.20-compact i586; 80x30)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre5; Linux 2.2.20 i586; 138x44)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre5; Linux 2.4.23 i686; 114x27)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre5; Linux 2.4.24 i686; 132x34)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre5; Linux 2.6.0 i686; 176x66)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.9.3)" + family: "Links" + major: '0' + minor: '9' + patch: + - user_agent_string: "ELinks (0.9.CVS; Linux 2.6.5 i686; 169x55)" + family: "Links" + major: '0' + minor: '9' + patch: + - user_agent_string: "ELinks/0.9.CVS (textmode; Linux 2.4.18-1-386 i686; 80x25-3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; FreeBSD 4.10-PRERELEASE i386; 132x43)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; FreeBSD 4.10-STABLE i386; 132x43)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; Linux 2.4.26 i686; 128x48)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; Linux 2.6.3-7mdksmp i686; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; Linux 2.6.6 i686; 128x54)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; Linux; 80x24)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; Linux; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.2rc2 (textmode; Linux 2.4.26-lck1 i486; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.2rc4 (textmode; Linux 2.4.20-8 i686; 105x46)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.2rc7 (textmode; Linux 2.4.29-1 i686; 190x75)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.2 (textmode; Linux; 157x52)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3 (textmode; Linux 2.6.10 i686; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3 (textmode; Linux 2.6.7-20050106 i686; 80x34)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3 (textmode; Linux 2.6.8-1-386 i686; 160x64)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3 (textmode; Linux 2.6.8.1 i686; 118x82)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3 (textmode; Linux 2.6.8-mdp04 i686; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Enigma Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "EricssonT68/R101 (;; ;; ;; Smartphone; SDA/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Explorer /5.02 (Windows 95; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Explorer /5.02 (Windows 95; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; FastWeb; Windows NT 5.1; OMEGA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "FavOrg" + family: "Other" + major: + minor: + patch: + - user_agent_string: "FDM 1.x" + family: "Other" + major: + minor: + patch: + - user_agent_string: "FindAnISP.com_ISP_Finder_v99a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "findlinks/0.901e (+http://wortschatz.uni-leipzig.de/findlinks/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Firefox/1.0 (Windows; U; Win98; en-US; Localization; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Firefox/1.0.1 (Windows NT 5.1; U; pl-PL)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "FireFox (X11; Linux i686; pl-PL); slackware; FireFox;" + family: "Other" + major: + minor: + patch: + - user_agent_string: "FlashGet" + family: "Other" + major: + minor: + patch: + - user_agent_string: "FOOZWAK (zeep; 47.3; CheeseMatic 9.1; T312461; iOpus-I-M; BucketChunk 4.1; Shronk; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "FreshDownload/4.40" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Funky Little Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Galeon (IE4 compatible; Galeon; Windows XP)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Galeon (PPC; U; Windows NT 5.1; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Galeon; Windows NT 5.1;)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (IE4 compatible; Galeon; Windows NT 5.1;)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (IE4 compatible; Galeon; Windows XP)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 Galeon 1.2.5 (X11; Linux i686; U;) Gecko/0-pie MSIE 6.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-IE; rv:1.6) Gecko Galeon" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 Galeon/1.0.2 (X11; Linux i686; U)" + family: "Galeon" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U)" + family: "Galeon" + major: '1' + minor: '0' + patch: '3' + - user_agent_string: "Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U;) Gecko/20020214" + family: "Galeon" + major: '1' + minor: '0' + patch: '3' + - user_agent_string: "Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U;) Gecko/20020325" + family: "Galeon" + major: '1' + minor: '0' + patch: '3' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.0 (X11; Linux i686; U)" + family: "Galeon" + major: '1' + minor: '2' + patch: '0' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.0 (X11; Linux i686; U;) Gecko/20020408" + family: "Galeon" + major: '1' + minor: '2' + patch: '0' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/0" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/20030417" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/20030703" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/20030708" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/20030716" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/20030822" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.13 (X11; Linux i686; U;) Gecko/20040308" + family: "Galeon" + major: '1' + minor: '2' + patch: '13' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.13 (X11; Linux i686; U;) Gecko/20041004" + family: "Galeon" + major: '1' + minor: '2' + patch: '13' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i586; U;) Gecko/20020605" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U)" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/0" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/20020605" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/20020623 Debian/1.2.5-0.woody.1" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/20020809" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20020827" + family: "Galeon" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20020830" + family: "Galeon" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20021105" + family: "Galeon" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20021203" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20021226 Debian/1.2.7-6" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20030131" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20030401" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20030622" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux ppc; U;) Gecko/20030130" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.8 (X11; Linux i686; U;) Gecko/20030317" + family: "Galeon" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.8 (X11; Linux i686; U;) Gecko/20030328" + family: "Galeon" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031114 Galeon/1.3.10" + family: "Galeon" + major: '1' + minor: '3' + patch: '10' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Galeon/1.3.10 (Debian package 1.3.10-3)" + family: "Galeon" + major: '1' + minor: '3' + patch: '10' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Galeon/1.3.11a (Debian package 1.3.11a-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '11' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Galeon/1.3.11a (Debian package 1.3.11a-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '11' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040814 Galeon/1.3.11a" + family: "Galeon" + major: '1' + minor: '3' + patch: '11' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040115 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20031015 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040308 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040331 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hu; rv:1.6) Gecko/20040229 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.6) Gecko/20040115 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031115 Galeon/1.3.13" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040116 Galeon/1.3.13" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Galeon/1.3.13 (Debian package 1.3.13-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Galeon/1.3.13 (Debian package 1.3.13-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040130 Galeon/1.3.13" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040305 Galeon/1.3.13" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312 Galeon/1.3.13 (Debian package 1.3.13-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040402 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040426 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040501 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040928 Galeon/1.3.14 (Debian package 1.3.14a-0jds4)" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20040107 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Galeon/1.3.14 (Debian package 1.3.14a-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040124 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040309 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Galeon/1.3.14 (Debian package 1.3.14a-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Galeon/1.3.14 (Debian package 1.3.14acvs20040504-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040528 Galeon/1.3.14 (Debian package 1.3.14acvs20040520-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (compatible; Galeon/1.3.15; Atari 2600)" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Galeon/1.3.15 (Debian package 1.3.15-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Galeon/1.3.15" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040528 Galeon/1.3.15 (Debian package 1.3.15-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040618 Galeon/1.3.15" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040624 Galeon/1.3.15" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040624 Galeon/1.3.15 (Debian package 1.3.15-3)" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040710 Galeon/1.3.16" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Galeon/1.3.16" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040726 Galeon/1.3.16 (Debian package 1.3.16-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040802 Galeon/1.3.16 (Debian package 1.3.16-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040805 Galeon/1.3.16 (Debian package 1.3.16-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040810 Galeon/1.3.16 (Debian package 1.3.16-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040724 Galeon/1.3.16" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20040824 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040805 Galeon/1.3.17 (Debian package 1.3.17-2.0.1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040818 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040820 Galeon/1.3.17 (Debian package 1.3.17-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040906 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040921 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Galeon/1.3.17 (Debian package 1.3.17-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.2) Gecko/20040808 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041130 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041221 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041224 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20041007 Galeon/1.3.18 (Debian package 1.3.18-1.1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041228 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040916 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040922 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040928 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Galeon/1.3.18 (Debian package 1.3.18-1.1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041020 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041223 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.18 (Debian package 1.3.18-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.3) Gecko/20041007 Galeon/1.3.18 (Debian package 1.3.18-1.1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (This is not Lynx/Please do not arrest user; X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041027 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041224 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041020 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041027 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.19 (Debian package 1.3.19-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.19 (Debian package 1.3.19-3)" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.19 (Debian package 1.3.19-4)" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050106 Galeon/1.3.19 (Debian package 1.3.19-1ubuntu1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050216 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041230 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050106 Galeon/1.3.19 (Debian package 1.3.19-3)" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041221 Galeon/1.3.19.99" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.20 (Debian package 1.3.20-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '20' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050106 Galeon/1.3.20 (Debian package 1.3.20-1ubuntu4)" + family: "Galeon" + major: '1' + minor: '3' + patch: '20' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050324 Galeon/1.3.20 (Debian package 1.3.20-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '20' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586) Gecko/20030311 Galeon/1.3.3" + family: "Galeon" + major: '1' + minor: '3' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030311 Galeon/1.3.3" + family: "Galeon" + major: '1' + minor: '3' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030428 Galeon/1.3.3" + family: "Galeon" + major: '1' + minor: '3' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386) Gecko/0 Galeon/1.3.4" + family: "Galeon" + major: '1' + minor: '3' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586) Gecko/20030807 Galeon/1.3.5" + family: "Galeon" + major: '1' + minor: '3' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030530 Galeon/1.3.5" + family: "Galeon" + major: '1' + minor: '3' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030807 Galeon/1.3.5" + family: "Galeon" + major: '1' + minor: '3' + patch: '5' + - user_agent_string: "Galeon/1.3.7 (IE4 compatible; Galeon; Windows XP) Galeon/1.3.7 Debian/1.3.7.20030803-1" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Galeon/1.3.7 (IE4 compatible; I; Mac_PowerPC)" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Galeon/1.3.7 (IE4 compatible; I; Windows XP) Galeon/1.3.7 Debian/1.3.7.20030803-1" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386) Gecko/0 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030610 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030630 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20040107 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20040319 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20040323 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20040428 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.4) Gecko/20030630 Galeon/1.3.8" + family: "Galeon" + major: '1' + minor: '3' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.4) Gecko/20030630 Galeon/1.3.8" + family: "Galeon" + major: '1' + minor: '3' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030630 Galeon/1.3.8" + family: "Galeon" + major: '1' + minor: '3' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4) Gecko/20030630 Galeon/1.3.8" + family: "Galeon" + major: '1' + minor: '3' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4) Gecko/20030630 Galeon/1.3.8" + family: "Galeon" + major: '1' + minor: '3' + patch: '8' + - user_agent_string: "Galeon/1.3.9 Mozilla/1.4 HTML/4.01 XHTML/1.0 CSS/2.1" + family: "Galeon" + major: '1' + minor: '3' + patch: '9' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030915 Galeon/1.3.9" + family: "Galeon" + major: '1' + minor: '3' + patch: '9' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031015 Galeon/1.3.9" + family: "Galeon" + major: '1' + minor: '3' + patch: '9' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.4) Gecko/20030930 Galeon/1.3.9" + family: "Galeon" + major: '1' + minor: '3' + patch: '9' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030311 Galeon/1.3.3,gzip(gfe) (via translate.google.com)" + family: "Galeon" + major: '1' + minor: '3' + patch: '3' + - user_agent_string: "GetRight/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "GetRight/5.0.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "GetRight/5.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Go-Ahead-Got-It/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "googlebot/2.1 (+http://www.googlebot.com/bot.html" + family: "Other" + major: + minor: + patch: + - user_agent_string: "googlebot/2.1; +http://www.google.com/bot.html" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Googlebot (+http://www.google.com/bot.html)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Googlebot/2.1 (compatible; MSIE; Windows)" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Googlebot/2.1 (+http://www.googlebot.com/bot.html) (compatible; MSIE 6.0; )" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Googlebot/2.1+(+http://www.google.com/bot.html)" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (MobilePhone SCP-5500/US/1.0) NetFront/3.0 MMP/2.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (MobilePhone SCP-5500/US/1.0) NetFront/3.0 MMP/2.0 FAKE (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.)" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "GoogleBot/2.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Googlebot-Image/1.0 (+http://www.googlebot.com/bot.html" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; grub-client-2.6.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Grubclient-2.2-internal-beta)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Grubclient; windows; SV1; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "grub crawler" + family: "Other" + major: + minor: + patch: + - user_agent_string: "grub crawler(http://www.grub.org)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "gsa-crawler (Enterprise; GID-01742;gsatesting@rediffmail.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Happy-Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "HLoader" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Homerweb" + family: "Other" + major: + minor: + patch: + - user_agent_string: "HooWWWer/2.1.0 (+http://cosco.hiit.fi/search/hoowwwer/ | mailto:crawler-infohiit.fi)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Hop 0.7 (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Hozilla/9.0 (Macintosh; U; PC Mac OS X; en-us) SnappleWebKit/69 (KHTML, like your mom) Safari/69" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Win95; I; HTTPClient 1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Hyperlink/2.5e (Commodore 64)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ia_archiver-web.archive.org" + family: "Other" + major: + minor: + patch: + - user_agent_string: "alpha/06 (compatible; IBrowse; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IBrowse (AmigaOS; alpha/06; AmigaOS mod-x)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IBrowse(compatible; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IBrowse (compatible; alpha/06; AmigaOS/PPC; SV1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IBrowse/1.12demo (AmigaOS 3.0)" + family: "IBrowse" + major: '1' + minor: '12' + patch: + - user_agent_string: "IBrowse/2.2 (Windows V45)" + family: "IBrowse" + major: '2' + minor: '2' + patch: + - user_agent_string: "IBrowse/2.2 (Windows V50)" + family: "IBrowse" + major: '2' + minor: '2' + patch: + - user_agent_string: "IBrowse/2.3 (AmigaOS 3.0)" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "IBrowse/2.3 (AmigaOS 3.1)" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "IBrowse/2.3 (AmigaOS 3.9)" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "IBrowse/2.3 (AmigaOS 3.9))" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "IBrowse/2.3 (AmigaOS 4.0)" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; IBrowse 2.3; AmigaOS4.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AmigaOS4.0) IBrowse 2.3" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; IBrowse 3.0; AmigaOS4.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "iCab" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.1; Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '1' + - user_agent_string: "iCab/2.9.5 (Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '5' + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.6; Macintosh; U; PPC)" + family: "iCab" + major: '2' + minor: '9' + patch: '6' + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.7; Macintosh; U; PPC)" + family: "iCab" + major: '2' + minor: '9' + patch: '7' + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.7; Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '7' + - user_agent_string: "iCab/2.9.8 (Macintosh; U; PPC)" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "iCab/2.9.8 (Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "Mozilla/4/5 (compatible; iCab 2.9.8; Macintosh; U; 68K" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.8; Macintosh; U; PPC)" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.8; Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "Mozilla/5.0 (compatible; iCab 2.9.8; Macintosh; U, PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "iCab/3.0 (Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; iCab 3.0; Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '3' + minor: '0' + patch: + - user_agent_string: "ICE Browser/5.05 (Java 1.4.1; Windows 2000 5.0 x86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ICEBrowser 5.31" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ICE Browser/v5_4_3 (Java 1.4.2_01; Windows XP 5.1 x86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ICE Browser/v5_4_3_1 (Java 1.4.2_01; Windows XP 5.1 x86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IEAutoDiscovery" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IE test" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Internet Explorer 5x" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Internet Explorer 5.x" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IQSearch" + family: "Other" + major: + minor: + patch: + - user_agent_string: "itunes" + family: "Other" + major: + minor: + patch: + - user_agent_string: "iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "iTunes/4.7 (Macintosh; U; PPC Mac OS X 10.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/2.0final" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/2.0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/2.0rc1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/2.0rc2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/3.0-beta1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/3.0-rc1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/2.0.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java(TM) 2 Runtime Environment, Standard Edition" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java1.1.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java1.3.1_03" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java1.4.0_02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.1_01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.1_02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.1_04" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.1_05" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2_01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2_03" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2_04" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2_05" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2_06" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.5.0_01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.5.0-beta2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "jBrowser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "JoBo/1.4beta (http://www.matuschek.net/jobo.html)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "JoeDog/1.00 [en] (X11; I; Siege 2.59)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Kittiecentral.com; HTTP)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Kittiecentral.com; HTTPConnect)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Kittiecentral.com; Index-Client)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Klondike/1.50 (WSP Win32) (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "KnowItAll(knowitall@cs.washington.edu)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Konqueror" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror; FreeBSD; http://www.cartedaffaire.net/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Konqueror/1.1.2" + family: "Konqueror" + major: '1' + minor: '1' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.0.1; X11); Supports MD5-Digest; Supports gzip encoding" + family: "Konqueror" + major: '2' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)" + family: "Konqueror" + major: '2' + minor: '1' + patch: '1' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.1.2; X11)" + family: "Konqueror" + major: '2' + minor: '1' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2-11; Linux)" + family: "Konqueror" + major: '2' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.1)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.1; Linux)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.2)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.2-2; Linux)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.2; FreeBSD)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.2; Linux)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.2; Linux 2.4.14-xfs; X11; i686)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Konqueror 3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0.0-10; Linux)" + family: "Konqueror" + major: '3' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0.0; FreeBSD)" + family: "Konqueror" + major: '3' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0.0; Linux)" + family: "Konqueror" + major: '3' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0; Darwin)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020101)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020313)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3; FreeBSD)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3; Linux)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3; Linux; X11)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20021215)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0.0-10; Linux 2.4.18-3smp)" + family: "Konqueror" + major: '3' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0.1 (CVS >= 20020327); Linux) Linspire (Lindows, Inc.)" + family: "Konqueror" + major: '3' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; CYGWIN_NT-5.1)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; de)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; de, DE, de_DE@euro)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; FreeBSD)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20020802)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021111)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.20-4GB-athlon; X11; i686)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.20-4GB; X11)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.20; X11; i686)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.20-xfs; X11)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.21-20.0.1.ELsmp; X11; i686; , en_US, en, de)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.21-243-athlon)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-10mdk; X11; i686; en_GB, en_NZ, en)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-10mdk; X11; i686; fr, fr_FR)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-1.2115.nptl)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-4GB-athlon; X11; i686)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-aes; X11; i686)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-xfs; X11)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.24-xfs; X11)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; de, DE, de_DE@euro)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; en_US, en)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; i686)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; X11; de, DE, de_DE@euro)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; X11; en_GB)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; X11; i686; , en_US, en)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; X11; i686; uk, uk_UA)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; OpenBSD)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; SunOS)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1.3; OpenBSD 3.4)" + family: "Konqueror" + major: '3' + minor: '1' + patch: '3' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Darwin) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; , en_GB, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; en_US, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; FreeBSD 4.9-STABLE; X11; i386; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; FreeBSD) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2) KHTML/3.2.3 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.22) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.23-0; X11; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.24-xfs; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.25-klg; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.26; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.27; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.3-15mdksmp; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.3-7mdk) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.3-7mdk; X11; i686; en_US, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.4-52-default; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.4; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.5) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.5; X11; i686; en_US, es, fr, it, en_US.UTF-8, en)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.5; X11; i686; en_US, es, fr, it, en_US.UTF-8, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.5; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.7-rc3-love2; X11; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.7; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.8.1-10mdk) KHTML/3.2.3 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.8.1-12mdksmp) KHTML/3.2.3 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.8.1; X11; i686; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; de, de_DE@euro) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; en_GB, en_GB.UTF-8, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; en_GB, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; en_US, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; en_US, zh_TW, en_US.UTF-8, zh_TW.UTF-8, zh) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; i686; en_US, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux) KHTML/3.2.3 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; ) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko) WebWasher 3.3" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; , en_US, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; es, es_ES, es_ES.UTF8) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; ) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; ru, en_US, ru_RU, ru_RU.KOI8-R, KOI8-R) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; NetBSD) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; OpenBSD) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; x86_64; en_US) KHTML/3.2.3 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2.; Linux 2.4.20-gentoo-r2; X11; i" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2.2; Linux) (KHTML, like Gecko) - www.amorosi4u.de.vu" + family: "Konqueror" + major: '3' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2.3; FreeBSD 4.10-STABLE; X11; i386; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2.3; OpenBSD 3.6)" + family: "Konqueror" + major: '3' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; FreeBSD 5.3-RELEASE-p2; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; FreeBSD) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.4.21-243-smp4G) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; konqueror/3.3; linux 2.4.21-243-smp4G) (KHTML, like Geko)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.4.24; X11; i686; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.4.27; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-1-386; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-1-686-smp) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-1-686; X11; i686; zh_TW) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-1-k7; X11; i686; en_US) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-gentoo-r2-ljr; X11; x86_64; en_US) KHTML/3.3.91 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10; X11; i686; en_US) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10; X11; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.11.2; X11; i686; cs, en_US) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.7) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.7; X11; i686; fr, it, es, ru, de, en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.8.1-24mdk; X11; i686; sl) KHTML/3.3.92 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.8-1-686; X11; i686; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.8-2-686-smp) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.9-10.1.aur.4; X11; pl) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.9; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; de, en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; de) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux) KHTML/3.3.91 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux) KHTML/3.3.92 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; ppc) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; X11; i686; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; X11; i686; es, en_US) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; X11; i686) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; X11; x86_64; de) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; x86_64) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; pl, en_US) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; pl) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; X11; de) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.4; FreeBSD) KHTML/3.4.0 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '4' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.4; Linux 2.6.11-rc4; X11; en_US) KHTML/3.4.0 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '4' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.4; Linux; en_US) KHTML/3.4.0 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '4' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.0 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '4' + patch: + - user_agent_string: "Mozilla/6.0 (compatible; Konqueror/4.2; i686 FreeBSD 6.4; 20060308)" + family: "Konqueror" + major: '4' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020126)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020202)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020224)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020703)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020911)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20021022)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020719)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020510)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020710)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020609)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Kurzor/1.0 (Kurzor; http://adcenter.hu/docs/en/bot.html; cursor@easymail.hu)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Lament/7.8 (compatible; Netscape 5.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "larbin_2.6.3 (larbin-2.6.3@unspecified.mail)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "larbin_2.6.3 larbin-2.6.3@unspecified.mail" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LB-Crawler/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LG/U8110/v2.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "fetch libfetch/2.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "libwww-perl/5.79" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT306/R101 [Html2Wml/0.4.11 libwww-perl/5.79]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "testJapanequeDelicious/0.1 libwww-perl/5.803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "W3C-checklink/4.1 [4.14] libwww-perl/5.803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; Linkman)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Links" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Links (030709; Linux 2.6.7-bootsplash i686; fb)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LINKS Mozilla/2.0 (compatible; MSIE 10.0)" + family: "IE" + major: '10' + minor: '0' + patch: + - user_agent_string: "Links (0.92; Linux 2.2.14-5.0 i586)" + family: "Links" + major: '0' + minor: '92' + patch: + - user_agent_string: "Links (0.96; Linux 2.4.9-e.38.1RS i686)" + family: "Links" + major: '0' + minor: '96' + patch: + - user_agent_string: "Links (0.96; Unix)" + family: "Links" + major: '0' + minor: '96' + patch: + - user_agent_string: "Links (0.97pre3; Linux 2.4.18-6mdk i586)" + family: "Links" + major: '0' + minor: '97' + patch: + - user_agent_string: "Links (0.98; Darwin 7.6.0 Power Macintosh; 90x50)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links/0.98 (fdafsd; Unix; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Links (0.98; Linux 2.2.25 i586; 100x37)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links (0.98; Linux 2.4.20 i686; 80x34)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links (0.98; Linux 2.4.25-20040331b i686; 80x50)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links (0.98; Unix)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links (0.98; Unix; 100x37)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links (0.99; Linux 2.6.8.1-4-386 i686; 198x66)" + family: "Links" + major: '0' + minor: '99' + patch: + - user_agent_string: "Links (0.99pre14; CYGWIN_NT-5.1 1.5.10(0.116/4/2) i686; 111x39)" + family: "Links" + major: '0' + minor: '99' + patch: + - user_agent_string: "Links (0.99pre8; Unix; 80x25)" + family: "Links" + major: '0' + minor: '99' + patch: + - user_agent_string: "Links (1.00pre10; Darwin 5.5 Power Macintosh; 80x24)" + family: "Links" + major: '1' + minor: '00' + patch: + - user_agent_string: "Links (1.00pre12; Linux 2.6.10-grsec i686; 139x54) (Debian pkg 0.99+1.00pre12-1)" + family: "Links" + major: '1' + minor: '00' + patch: + - user_agent_string: "Links (1.00pre12; Linux 2.6.2 i586; 80x24) (Debian pkg 0.99+1.00pre12-1)" + family: "Links" + major: '1' + minor: '00' + patch: + - user_agent_string: "Links (1.00pre3; SunOS 5.9 i86pc; 80x24)" + family: "Links" + major: '1' + minor: '00' + patch: + - user_agent_string: "Links (2.0; FreeBSD 4.7-RELEASE i386; 80x24)" + family: "Links" + major: '2' + minor: '0' + patch: + - user_agent_string: "Links 2.0 (http://gossamer-threads.com/scripts/links/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Links (2.0pre1; Linux 2.4.24-grsec i686; 80x25)" + family: "Links" + major: '2' + minor: '0' + patch: + - user_agent_string: "Links (2.0pre6; Linux 2.2.16 i686; x)" + family: "Links" + major: '2' + minor: '0' + patch: + - user_agent_string: "Links (2.1pre11; FreeBSD 4.9-RELEASE i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; FreeBSD 5.2.1-RELEASE i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.20-20.7asp i686; 80x24)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.22-10mdk i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.24 i686; 87x32)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.25-gentoo-r2 i686; 100x37)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.25-gentoo-r2 i686; 160x64)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.26-gentoo-r6 i686; 122x43)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.6.5-gentoo i686; 122x40)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.6.6-rc1 i686; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.6.7-gentoo-r14 i686; fb)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.6.7-ide4 i586; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre12; Linux 2.2.19-7.0.16smp i686; 128x47)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre13; Linux 2.4.7-10 i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre13; Linux 2.6.3-4mdk i686; 100x37)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; FreeBSD 4.9-RELEASE i386; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; FreeBSD 5.1-RELEASE i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; FreeBSD 5.2.1-RELEASE i386; 80x50)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; Linux 2.4.26-bsd21h i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; Linux 2.6.4-52-default i686; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; Linux 2.6.4-54.5-default i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; Linux 2.6.5-7.104-default i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; Linux 2.6.5 i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; OpenBSD 3.4 i386)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; OpenBSD 3.6 i386)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; CYGWIN_NT-5.0 1.3.1(0.38/3/2) i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 4.10-RELEASE i386; 131x85)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 4.10-RELEASE i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 5.2-CURRENT i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 5.3-RELEASE i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 5.3-RELEASE i386; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 5.3-RELEASE-p5 i386; 78x28)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 5.3-STABLE i386; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.2.14-5.0 i586; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.2.16 i586; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.18-27.7.x i586; svgalib)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.22-1.2115.nptl i686; braille)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.26 i586; 128x48)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.26 i686; 128x48)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.26 i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.27 i586; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.10-gentoo-r4 i686; 141x52)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.10-gentoo-r4n i686; fb)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.10-gentoo-r5 i686; 100x38)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.10-gentoo-r6 i686; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.6tlahuizcalpacuhtli i486; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.9-gentoo-r1-g4 ppc; 160x53)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.9-gentoo-r1 i686; 128x48)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.9-gentoo-r1 x86_64; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.9 i686; 128x48)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; NetBSD 2.99.11 amd64; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; OpenBSD 3.6 i386; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre16; Linux 2.6.9-buz i686; 128x47)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre17; FreeBSD 5.4-PRERELEASE i386; 80x60)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre17; Linux 2.4.18-rmk7-pxa3-embedix armv5tel; 73x33)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre7; Linux 2.6.9 i686; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre9; Linux 2.4.25 i686; fb)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre; Linux)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "LinkSweeper/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Linspire Internet Suite" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lmspider (lmspider@scansoft.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Lotus-Notes/5.0; Windows-NT)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Lotus-Notes/6.0; Windows-NT)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH/3.02a (http://www.learntohack.nil)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH browser 3.02a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser 3.02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser/3.02a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser 3.02a (compatible; mozilla ; Windows NT 5.1; SV1; http://www.learntohack.nil; .NET CLR 1.1.4322; http://www.learntohack.nil)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser 3.02a (compatible; MSIE 6.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "LTH Browser 3.02a (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://www.learntohack.nil; .NET CLR 1.1.4322; http://www.learntohack.nil)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "LTH Browser 3.02a (http://www.learntohack.nil)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser/3.02a (http://www.learntohack.nil)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser/3.02 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lwp-request/2.06" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LWP::Simple/5.50" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LWP::Simple/5.68" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LWP::Simple/5.76" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LWP::Simple/5.79" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LWP::Simple/5.800" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lwp-trivial/1.34" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lwp-trivial/1.38" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lwp-trivial/1.40" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lwp-trivial/1.41" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Lynx (compatible; MSIE 6.0; )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Lynx (SunOS 10)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Lynx/1.025 (CP/Build 16-bit)" + family: "Lynx" + major: '1' + minor: '025' + patch: + - user_agent_string: "Lynx/2.2 libwww/2.14" + family: "Lynx" + major: '2' + minor: '2' + patch: + - user_agent_string: "Lynx/2.6 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '6' + patch: + - user_agent_string: "Lynx/2.7.1ac-0.102+intl+csuite libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '7' + patch: '1' + - user_agent_string: "Lynx/2.7.1 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '7' + patch: '1' + - user_agent_string: "Lynx/2.7.2 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '7' + patch: '2' + - user_agent_string: "Lynx/2.8 (incompatible; NCSA HALOS; HAL9000" + family: "Lynx" + major: '2' + minor: '8' + patch: + - user_agent_string: "Lynx/2.8rel.2 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: + - user_agent_string: "Lynx/2.8.1rel.2 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '1' + - user_agent_string: "Lynx/2.8.2rel.1 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '2' + - user_agent_string: "Lynx/2.8.3dev.18 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3dev.6 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3dev.8 libwww-FM/2.14FM" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3dev.9 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3rel.1 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3rel.1 libwww-FM/2.14FM" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.4" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3rel.1 libwww-FM/2.14 SSL-MM/1.4 OpenSSL/0.9.6" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.4rel.1" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 Dillo/0.7.3 pl (X11; Linux)" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/0.8.6" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6a" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6b" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6c" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6e" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6g" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7a" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7b" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7c" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1-mirabilos libwww-FM/2.14FM SSL-MM/1.4.1 OpenSSL/0.9.6c" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.5dev.12 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7a" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.16 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.16 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6b" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.16 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7a" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.2 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6a" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.7 libwww-FM/2.14 SSL-MM/1.4.1" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.7 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6b" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.7 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.7 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7a" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.8 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6g" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.9 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7-beta3" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/0.8.12" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.0.16" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7c" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7d" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.2 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7d" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.6dev.11 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7d" + family: "Lynx" + major: '2' + minor: '8' + patch: '6' + - user_agent_string: "Lynx/2.8.6dev.6 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7d" + family: "Lynx" + major: '2' + minor: '8' + patch: '6' + - user_agent_string: "LynX 0.01 beta" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MacNetwork/1.0 (Macintosh)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Metager2 (http://metager2.de/site/webmaster.php)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MicroSux 6.6.6 (fucked up v9.1) 2 bit" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Minstrel-Browse/1.0 (http://www.minstrel.org.uk/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Missigua Locator 1.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MnoGoSearch/3.2.31" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mosaic for Amiga/1.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.0 (compatible; NCSA Mosaic; Atari 800-ST)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mosaic/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/1.0 (X11; FreeBSD 1.2.0 i286) via proxy gateway CERN-HTTPD/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.0 (compatible; MSIE 6.0;Windows XP),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "NCSA_Mosaic/2.0 (Windows 3.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.0 (Windows NT 5.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mosaic/2.1 (Amiga ARexx)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mosaic/2.1 (compatible; MSIE; Amiga ARexx; SV1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.7b5 (X11;Linux 2.0.13 i386) libwww/2.12 modified" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA Mosaic/2.7b5 (X11;Linux 2.6.7 i686) libwww/2.12 modified" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.7b5 (X11;Linux 2.6.7 i686) libwww/2.12 modified" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA Mosaic/2-7-6 (X11;OpenVMS V7.2 VAX)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Mosaic/2.8; Windows NT 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.8 (X11; FreeBSD 5.2.1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA Mosaic/3.0.0 (Windows x86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AIR_Mosaic(16bit)(demo)/v3.09.05.08" + family: "Other" + major: + minor: + patch: + - user_agent_string: "mMosaic/3.6.6 (X11;SunOS 5.8 sun4m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MOT-V551/08.17.0FR MIB/2.2.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MovableType/3.0D" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozdex/0.06-dev (Mozdex; http://www.mozdex.com/bot.html; spider@mozdex.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "mozilla (compatible; MSIE 3.0; Mac_PowerPC)" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "alpha/06" + family: "Other" + major: + minor: + patch: + - user_agent_string: "alpha/06 (AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "alpha/06 (compatible; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ALPHA/06 (compatible; ALPHA/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ALPHA/06 (compatible; Win98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaOS 3.4 S.E.K-Tron" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaOS 5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/0.001 (uncompatible; TuringOS; Turing Machine; 0.001; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/0.02 [fu] (Dos62; Panzer PzKpfw Mk VI; SK Yep, its official I'm a nazi, or an asshat whichever.)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/0.1 [es] (Windows NT 5.1; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.000 (AOS; U; en) Gecko/20050301" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.0 (Macintosh; 68K; U; en)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.1N (X11; I; SunOS 5.4 sun4m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.4.1 (windows; U; NT4.0; en-us) Gecko/25250101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.6 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040812 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla 1.7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla 1.7.2 (FreeBSD 5.2.1) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla 1.75 on Linux: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.01 (Win16; I) via HTTP/1.0 deep.space.star-travel.org/" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.0 (compatible ; MSIE 3.02; Windows CE; PPC; 240x320)" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/24.4 (X11; I; Linux 2.4 i686; U) [en-ES]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01-C-MACOS8 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01SGoldC-SGI (X11; I; IRIX 6.3 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04Gold (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04 (Win16; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04 (Win16; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04 (X11; I; SunOS 5.5.1 sun4u) via HTTP/1.0 depraved-midget.onlinescanner.com/" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (DreamKey/2.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 [en] (AWV2.20f)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Liberate DTV 1.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Planetweb/2.100 JS SSL US; Dreamcast US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Windows 98;U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Windows 98; Win 9x 4.90)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (x86 [en] Windows NT 5.1; Sun)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.x (I-Opener 1.1; Netpliance)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (0000000000; 0000 000; 0000000 00 000)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (0000000000; 0000 0000; 00000000000)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.00 [en] (Compatible; RISC OS 4.39; MSIE 5.01; Windows 98; Oregano 1.10)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (6; probably not the latest!; Windows 2005; H010818)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (AmigaOS 3.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (combatible; MSIE 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; alpha 06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ALPHA/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; AmigaOS; Chimera)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; GoogleToolbar 2.0.113-big; Windows XP 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ICS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; IE-Favorites-Check-0.5)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Mozilla 4; Linux; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0b1; X11; I; Linux 2.4.18 i686)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98)Gecko/20020604" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (Compatible; MSIE 5.5; Windows NT 4.0; QXW03002)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (Compatible; MSIE 5.5; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 ( compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AmigaOs)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla /4.0 (compatible; MSIE 6.0; i686 Linux)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; NetBSD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (Compatible; MSIE 6.0; SunOS 5.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (Compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 7.1; Windows NT 7.1; Blueberry Bulid 2473)" + family: "IE" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (Compatible; Windows_NT 5.0; MSIE 6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (exemplo; msiex; amiga)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (fantomBrowser)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 ( http://www.brismee.com/ ; mailto:guy.brismee@advalvas.be ; NSA/666.666.666 ; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 ( http://www.brismee.com/ ; mailto:guy.brismee@laposte.net ; NSA/666.666.666 ; SV1; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (JemmaTheTourist;http://www.activtourist.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 look-alike" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (Macintosh; U; PPC Mac OS X; en)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (MobilePhone SCP-5500/US/1.0) NetFront/3.0 MMP/2.0" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (Mozilla/4.0; 6.0; MSIE 6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (MSIE/6.0; compatible; Win98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1; .NET CLR 1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (PDA; SL-C860/1.0,OpenPDA/Qtopia/1.3.2) NetFront/3.0" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (PDA; Windows CE/1.0.0) NetFront/3.0" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (PDA; Windows CE/1.0.1) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (); ; ; ()" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (SKIZZLE! Distributed Internet Spider v1.0 - www.SKIZZLE.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (SmartPhone; Symbian OS/0.9.1) NetFront/3.0" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (stat 0.12) (statbot@gmail.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (SunOS 5.8)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (Windows NT 4.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (Windows XP 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20040803 Debian-1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla 4.75 [en] (X11; I; Linux 2.2.25 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla 4.8 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla 5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0 000000; 00000; 00000000) 00000000000000 0000000000" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0; 00000) 000000000000000 0000000 0000 000000 0000000000" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0; 00) 0000000000000000000 0000000 0000 000000 0000000000000" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0; 00000) 0000000000000000000 0000000 0000 000000 0000000000000" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0 000000; 00000; 00000000) 00000000000000 00000000000 000000000000000000" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0; 00000) 0000000000000000000 0000000 0000 000000 0000000000000,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.001 (Macintosh; N; PPC; ja) Gecko/25250101 MegaCorpBrowser/1.0 (MegaCorp, Inc.)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.001 (windows; U; NT4.0; en-us) Gecko/25250101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0adfasdf" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (ALL YOUR BASE ARE BELONG TO US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (AmigaOS 3.5, Amiga, 0wnx0r3d by eric) Gecko/20020604" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (AmigaOS; sektron)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Atari; U; Atari 800; en-US) Gecko/20040206 Galaxian/2.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-CA; rv:1.5b) Gecko/20050308 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; 0.8) Gecko/20010208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.4) Gecko/20030701" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (CIA Secure OS; U; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Clustered-Search-Bot/1.0; support@clush.com; http://www.clush.com/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Mozilla/4.0; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Gecko/20050105 Debian/1.7.5-1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; X11; Linux i686; Konqueror/3.2) (KHTML, like Gecko) Gentoo/2004" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (DeadPeopleTasteLikeChicken.biz)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [de] (OS/2; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows NT 5.1; U; en-US;)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows; U; en-US; rv:1.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows; U; Win98; en-US; rv.0.9.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows; U; WinNT5.1; en-GB; rv:1.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows XP; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (FreeBSD; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Google-Gbrowser/0.0.9a; Windows NT 5.1; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Hector)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 IE" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (incompatible; MSIE 6.9; Secret OS 3.2; FIB;)" + family: "IE" + major: '6' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Java 1.4.1_05; Windows XP 5.1 x86; en) ICEbrowser/v6_0_0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Java 1.4.2_02; Windows XP 5.1 x86; en) ICEbrowser/v6_0_0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Java 1.4.2_05; Windows XP 5.1 x86; en) ICEbrowser/v5_2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (kombpartilb; Verhsun; Plasdfjoi; SV1; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Linux i386; en-US) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-EN; rv:0.9.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC;) Gecko DEVONtech" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; Incompatible my ass! What if I don't want your jerky, elitist, ugly-assed CSS crap? Screw you!)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.6 (KHTML, like Gecko) NetNewsWire/2.0b10" + family: "NetNewsWire" + major: '2' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.6 (KHTML, like Gecko) NetNewsWire/2.0b22" + family: "NetNewsWire" + major: '2' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0+(Macintosh;+U;+PPC+Mac+OS+X;+en)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/103u (KHTML, like Gecko) safari/100" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko, Safari) Shiira/0.9.1" + family: "Shiira" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko, Safari) Shiira/0.9.2" + family: "Shiira" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko, Safari) Shiira/0.9.2.2" + family: "Shiira" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.4 (KHTML, like Gecko, Safari) Shiira/0.9.2.2" + family: "Shiira" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.6 (KHTML, like Gecko, Safari) Shiira/0.9.3" + family: "Shiira" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit (KHTML, like Gecko) AIQtech" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit (KHTML, like Gecko) DEVONtech" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/124 (KHTML, like Gecko) safari/125.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.2 (KHTML, like Gecko, Safari) Shiira/0.9.2.2" + family: "Shiira" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.22" + family: "OmniWeb" + major: '563' + minor: '22' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.29" + family: "OmniWeb" + major: '563' + minor: '29' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.33" + family: "OmniWeb" + major: '563' + minor: '33' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.34" + family: "OmniWeb" + major: '563' + minor: '34' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v496" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v549" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558.43" + family: "OmniWeb" + major: '558' + minor: '43' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558.46" + family: "OmniWeb" + major: '558' + minor: '46' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558.48" + family: "OmniWeb" + major: '558' + minor: '48' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20020909 Chimera/0.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20030917 Camino/0.7" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.6 (KHTML, like Gecko, Safari) Shiira/0.9.3" + family: "Shiira" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; da-DK; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.2b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050331 Camino/0.8.3" + family: "Camino" + major: '0' + minor: '8' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a5) Gecko/20041114 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a5) Gecko/20041121 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041201 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20050103 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050224 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050317 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050401 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050115 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050127 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050130 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050131 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050203 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050217 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O) Gecko Camino" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; it-IT; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; zh-tw) AppleWebKit/125.5.6 (KHTML, like Gecko, Safari) Shiira/0.9.3" + family: "Shiira" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (MSIE 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (MSIE 6.0) Gecko/20011018" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla 5.0 (MSIE 6.0 Win 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (NetBSD 1.6.2; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (NetWare; U; NetWare 6.0.04; en-PL) ICEbrowser/5.4.3 NovellViewPort/3.4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (No data found)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (not MSIE5.5; X11; U; HP-UX 9000/785; en-US; rv:1.1) Gecko/20020828" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 3; en-US; rv:1.6) Gecko/20040117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.7.5) Gecko/20041220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.8a2) Gecko/20040719" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4; da-DK; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (ROIL FF/1.0; Windows NT 5.1 64-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (RSS Reader Panel)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Sage)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (tTh @ Cette) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (U; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Unknown; 32-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (U; PPC; en) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Version: 1251 Type:4565)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Version: 245 Type:180)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Version: 3247 Type:3276)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Version: 4445 Type:1763)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (VMS; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows 3.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; en-CA) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; rv:1.7.5) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1,de-DE)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win3.1; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-AT; 0.7) Gecko/20010109" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.0; CMCE) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.2b) Gecko/20021016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.8.0.1c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/9.0" + family: "K-Meleon" + major: '9' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040707 MSIE/7.66" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a3) Gecko/20040817" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b2) Gecko/20050317 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b2) Gecko/20050329 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b) Gecko/20050217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:7.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; hu; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.7.6) Gecko/20050319" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; PL; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pt-BR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; sv-SE; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; sv-SE; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; PL; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; pt-BR; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; Bush knew, failed to act.)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041108 STFU/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; el-GR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041110 FireFox/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; 0.7) Gecko/20010109" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; Like Navigator 6.2) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20020923 Phoenix/0.1" + family: "Phoenix" + major: '0' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20020929 Phoenix/0.2" + family: "Phoenix" + major: '0' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5b) Gecko/20030823 Mozilla Firebird/0.6.1+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040803 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910 Mnenhy/0.6.0.101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.0.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.1.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.4) Gecko/20041002" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.4) Gecko/20041010 FireFox/0.9b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.4) Gecko/20041010 K-Meleon/0.9b" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Plasmahuman/1.0 (Firefox 1.0 Get it. Now.)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.2d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040621" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a4) Gecko/20040927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a5) Gecko/20041122,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a5) Gecko/20041122 MultiZilla/1.7.0.0o" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050109" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050110" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050111 Mnenhy/0.7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050314 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050323 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050330 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050211" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050216" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.5) Gecko/20041108 Clab_Browser_1.0_www.cristalab.com/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fi-FI; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.8a6+) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.8b+) Gecko/20050117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.6) Gecko/20050311 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nl-NL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nl-NL; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.2) Gecko/20040803 Mnenhy/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; PL; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pt-BR; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pt-BR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.7.4) Gecko/20040926" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; tr-TR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-TW; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ca-AD; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.6) Gecko/20050318 Firefox/1.0.2 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.6) Gecko/20050330 Firefox/1.0.2 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.5) Gecko/20041108 Firefox/LukasHetzi" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8a3) Gecko/20040817" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041107 Junglelemming/4.3.7.1 (Wesma Pictures)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041122 Muuuh/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050223" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.8b2) Gecko/20050312 Firefox/1.0+ (tinderbox beast)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.0.1) Gecko/20020823" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.0.2) Gecko/20021120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2.1) Gecko/20021130,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040709" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.0.0d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 Sylera/2.1.20" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firechicken/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firematt/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Hypnotoad/1.0 (Firefox/1.0)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 IE/6.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Junglelemming/1.0 (Wesma Pictures)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Microsoft/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Mozilla/4.0/MSIE 6.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Mozilla/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107-RB Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.1c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.1j" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.8.0.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041219 Sylera/2.1.21" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041222 MOOX (M3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050308 Firefox/0.9.6" + family: "Firefox" + major: '0' + minor: '9' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 (All your Firefox/1.0.1 are belong to Firesomething)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firelemur/1.0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 CompeGPS/1.0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Hypnotoad/1.0.1 (Firefox/1.0.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Supergecko/1.0.1 (IE6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1 (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US, rv:1.7.6) Gecko/20050308 Firefox/1.0.1 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050312 Firefox/1.0.1 (stipe)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050314 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050315 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050317 Seastarfish/1.0.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050319" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050323" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050324 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 FairFox/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Unknow/x" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a4) Gecko/20040927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a5) Gecko/20041123 K-Meleon/0.9" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a5) Gecko/20041217 Mozilla Sunbird/0.2RC1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20040101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050107 MultiZilla/1.7.0.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050112" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050226" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050228 Firefox/1.0+ (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050307 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050313 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050315 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050319 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050320 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050321 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050330 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050401" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050128 Mnenhy/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050131 Firefox/1.0+ (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050201" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050202 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050205" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050217 MultiZilla/1.7.0.2d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:) Gecko/20040309" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US;) Unchaos/Crawler" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; eu-ES; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; eu-ES; rv:1.7.3) Gecko/20040910,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; eu-ES; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; eu-ES; rv:1.7.6) Gecko/20050225 Firefox/1.0.1,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041108 Mozilla/4.0/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041108 Mozilla /4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 2000)/1.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041109 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.0o" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.8)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; he-IL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hr-HR; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu-HU; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.6) Gecko/20050311 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ko-KR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.0.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.0.2) Gecko/20040823" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 xb0x/0.10.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sl-SI; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; uk-UA; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; cs-CZ; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041217 WebWasher 3.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8b2) Gecko/20050307 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; hu-HU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; ru-RU; rv:1.7.4) Gecko/20040926" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; ru-RU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; tr-TR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows, U, WinNT4.0, en-US, rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; es-ES; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; es-ES; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fi-FI; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; Windows 98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; ; Windows NT 5.1; rv:1.7.5) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux; en-US) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; DragonFly i386; en-US; rv:1.7.5) Gecko/20041112 Foobar/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; de-DE; rv:1.7.6) Gecko/20050322 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-GB; rv:1.7.5) Gecko/20041228" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030702" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030723" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20031008 Epiphany/1.0" + family: "Epiphany" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20031017" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5a) Gecko/20030926 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031203" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031207 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040128" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20040829" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20041016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041201 Epiphany/1.4.6" + family: "Epiphany" + major: '1' + minor: '4' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041204 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041219" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041221 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050103" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050108" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050112" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050118" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050124" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050305" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050306" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.6) Gecko/20050302 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.6) Gecko/20050315 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7a) Gecko/20040311" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040701 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20050314 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8a5) Gecko/20041214" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i686; en-US; rv:1.8a5) Gecko/20041106" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.6) Gecko/20040304" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.6) Gecko/20040816" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.6) Gecko/20040831" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/800; en-US; rv:1.4) Gecko/20030730" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 IP28; en-US; rv:1.7.5) Gecko/R-A-C Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 IP30; en-US; rv:1.7.5) Gecko/R-A-C Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 IP35; en-US; rv:1.7.5) Gecko/20041230" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.4.2-2 i686; en-US; 0.7) Gecko/20010316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.4.2 i686, en) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.6.11.4-gentoo-xD i686; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.6.3-FTSOJ i686; en-US; rv:1.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.6.4 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux; fr-FR; rv:1.6) Gecko/20040207 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.2) Gecko/20030708" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041209 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu4-warty99)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041219 Firefox/1.0 (Debian package 1.0+dfsg.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; it-IT; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; da-DK; rv:1.7.5) Gecko/20041221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686, de)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4.2) Gecko/20040921" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6; 009f52b638a35a83ea5212109fc44eed;) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040115 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.2) Gecko/20040906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041231" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20050125" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8a5) Gecko/20041121" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8a5) Gecko/20041122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8b2) Gecko/20050317" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.2) Gecko/20040906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050301 Firefox/1.0.1 (Debian package 1.0.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; el-GR; rv:1.7.5) Gecko/20041209 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu4-warty99)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.5) Gecko/20050312 Epiphany/1.4.8" + family: "Epiphany" + major: '1' + minor: '4' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.6) Gecko/20050315 Firefox/1.0 (Ubuntu package 1.0.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030401 Debian/1.0.2-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030821" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1; aggregator:Rojo; http://rojo.com/) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3.1) Gecko/20030721 wamcom.org" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040412" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040805" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20041004" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20041010" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20050104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030522 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030702" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20040206" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030903 Firebird/0.6.1+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031030 MultiZilla/1.5.0.3l" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031125" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031222" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040625" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040914 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20050202 Linspire/1.6-5.1.0.50.linspire2.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20041029" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.0.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040806" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040810" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040901" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040917" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040918 Epiphany/1.4.6" + family: "Epiphany" + major: '1' + minor: '4' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040919 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040920" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040921" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040924 Debian/1.7.3-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040924 Epiphany/1.4.4 (Ubuntu)" + family: "Epiphany" + major: '1' + minor: '4' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040929" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040930" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041001 Epiphany/1.2.9" + family: "Epiphany" + major: '1' + minor: '2' + patch: '9' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Epiphany/1.4.5" + family: "Epiphany" + major: '1' + minor: '4' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Epiphany/1.4.6" + family: "Epiphany" + major: '1' + minor: '4' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041019 MultiZilla/1.7.0.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041023" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041202 Debian/1.7.3.x.1-39" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20050112" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5;) Gecko/20020604 OLYMPIAKOS SFP" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 firefox/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 IE/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Microsoft/IE6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 MSIE/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.1" + family: "Firefox" + major: '1' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox (MSIE 6.0)/1.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Mozilla/1.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041118 Mozilla/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041217 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041217 Mnenhy/0.7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041217 msie" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.2d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041219" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041220 MultiZilla/1.7.0.1f" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041222" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041223" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041224" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041226" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041226 Epiphany/1.4.7" + family: "Epiphany" + major: '1' + minor: '4' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041227" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041228 Epiphany/1.4.6" + family: "Epiphany" + major: '1' + minor: '4' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041229" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041229 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041231" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Debian/1.4-6 StumbleUpon/1.87" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Epiphany/1.4.7" + family: "Epiphany" + major: '1' + minor: '4' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Epiphany/1.4.7 (Debian package 1.4.7-3)" + family: "Epiphany" + major: '1' + minor: '4' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 MultiZilla/1.7.0.1j" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050108" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050110 Spica/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050114 Microsoft/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050128" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050211 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050219 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050221 msie/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050223 Firefox/1.0 (Debian package 1.0.x.2-15)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050309" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050302 HypnoToad/1.0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050304 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050306 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050309 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050311 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050311 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050312 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050314 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050315 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050318 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050321 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050324 Debian/1.7.6-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050324 Epiphany/1.4.8 (Debian package 1.4.8-2)" + family: "Epiphany" + major: '1' + minor: '4' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050324 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050324 Firefox/1.0 (Ubuntu package 1.0.2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050325 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050328 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050401 Firefox/1.0.2 (Debian package 1.0.2-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040618 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040903 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040907 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040909 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20041027 NaverBot/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040729" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040817" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041121" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041124" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a6) Gecko/20050107 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b2) Gecko/20050227" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050314" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; SkipStone 0.8.4) Gecko/20020722" + family: "SkipStone" + major: '0' + minor: '8' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.5) Gecko/20031107 Debian/1.5-3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1 StumbleUpon/1.999" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.6) Gecko/20050312 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.4.2) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.3) Gecko/20041020" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4.3) Gecko/20041004" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.6) Gecko/20050315 Firefox/1.0 (Ubuntu package 1.0.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.7.5) Gecko/20041119 Firefox/1.0 (Debian package 1.0-3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.4.3) Gecko/20041004" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.3) Gecko/20040922" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ko-KR; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.6) Gecko/20040122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20050102" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20050111 Fedora/1.7.5-3.0.3.kde" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.6) Gecko/20050322 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.5) Gecko/20031020" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.7.3) Gecko/20040930" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Superholio/0.10.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041020 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041113 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20050329 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.6) Gecko/20050315 Firefox/1.0 (Ubuntu package 1.0.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; tr-TR; rv:1.7.2) Gecko/20040804 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i?86; en-US; rv:1.6) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.3) Gecko/20041207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux sparc; en-US; rv:1.5) Gecko/20041129" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; ca-AD; rv:1.7.5) Gecko/20050210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.3) Gecko/20041020" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050201" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050310" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050305" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; nl-NL; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.3) Gecko/20050117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.5) Gecko/20041205 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD macppc; en-US; rv:1.5) Gecko/20040102 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD macppc; en-US; rv:1.7.2) Gecko/20040825 Camino/0.8.1" + family: "Camino" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.2.1) Gecko/20030228" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040830 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20050110" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20050312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.7.6) Gecko/20050312 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; OpenVMS AlphaServer_ES40; en-US; rv:1.4) Gecko/20041126 FireFox/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OSF1 alpha; en-US; rv:1.4) Gecko/20030903" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.4) Gecko/20040126" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.4) Gecko/20040414" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7.3) Gecko/20040919" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7) Gecko/20041221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.2) Gecko/20021211" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4) Gecko/20041214" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.3) Gecko/20040914" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20050105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.6) Gecko/20050301 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.6) Gecko/20050313 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040629" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20041221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; fr-FR; rv:1.7.5) Gecko/2004" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; System/V-POSIX alpha; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; UNICOS/mk 21164a(EV5.6) Cray T3E; en-US; huelk) Gecko/20040413 SynLabs/0.6.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X) Gecko/20021016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.5 (compatible; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.666 [en] (X11; U; FreeBSD 4.5-STABLE i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.01 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (BEOS; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (6.0; comtemptible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (Atari 2600; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (Win32; Escape 5.03; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (Win32; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (X11; Linux 2.4.26 Sparc64) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (X11; Linux 2.6.10 Sparc 64) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (Linux; Escape/5.0; acentic client)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.1 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.1 [ja] (X11; I; Linux 2.2.13-33cmc1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.2 [en] (BeOS; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.2 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.00; msie" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.02 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.0 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.1 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.2 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7 [en] (Debian Sarge; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/9.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/9.0 (Atari2600; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/9.2 (Windows; U; Windows 3.11; en-US; rv:4.9.3) Gecko/20050213 Firefox/4.2" + family: "Firefox" + major: '4' + minor: '2' + patch: + - user_agent_string: "Mozilla/9.876 (alpha/06)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (compatible; X11; I; Linux 2.0.32 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla Epinard" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla FireFox (compatible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (FreeBSD 5.3-CURRENT)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (IE4 Compatible; I; Mac_PowerPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (IE5 Compatible; I; Mac_PowerPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla(IE Compatible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (larbin2.6.3@unspecified.mail)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla Windows" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (X11; E; Linux )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (X11; I; Linux 2.0.32 i286)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (X11; I; Linux 2.0.32 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SEKTron alpha/06; AmigaOS" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (X11; U; Linux 2.6.4; en-US; rv:0.9.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.2) Gecko/2001" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010628" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.2.1) Gecko/20010901" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.3) Gecko/20010801" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20010914" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20010923" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux sparc64; en-US; rv:0.9.4) Gecko/20011029" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4.2) Gecko/20021112 CS 2000 7.0/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.5) Gecko/20011018" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en US; rv:0.9.6+)Gecko/20011122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.6+) Gecko/20011122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:0.9.8) Gecko/20020204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:0.9.8) Gecko/20020204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.8) Gecko/20020204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (U; en-US; rv:0.9.9) Gecko/20020311" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020408" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020412 Debian/0.9.9-6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020501" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020513" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0rc1) Gecko/20020417" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc2) Gecko/20020510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc3) Gecko/20020523" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0rc2) Gecko/20020510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0rc3) Gecko/20020524" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.0) Gecko/20020605" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.0) Gecko/20020623 Debian/1.0.0-0.woody.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0+) Gecko/20020518" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020529" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020604" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020607" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020623 Debian/1.0.0-0.woody.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0; hi, Mom) Gecko/20020604" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.0.0) Gecko/20020529" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.0.0) Gecko/20020622 Debian/1.0.0-0.woody.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.0) Gecko/20020611" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20020730 AOL/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20020909" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20021023 Chimera/0.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20021219 Chimera/0.6+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.1) Gecko/20020830" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.0.1) Gecko/20020903" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020809" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020828" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020830" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020903" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021003" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021103" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20021216" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021216" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20021216" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030708" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030716" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20031013" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1a) Gecko/20020611" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1b) Gecko/20020721" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.1) Gecko/20021005" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.1) Gecko/20030102" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.1) Gecko/20030104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1a) Gecko/20020610" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.1) Gecko/20020827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.1) Gecko/20020927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.10 [en] (Compatible; RISC OS 4.37; Oregano 1.10)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Symbian OS/1.1.0)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2a) Gecko/20020910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20021016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2) Gecko/20021126" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.2) Gecko/20021204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2) Gecko/20021202" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2) Gecko/20021207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OSF1 alpha; en-US; rv:1.2) Gecko/20021205" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-GB; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; nl-NL; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.2.1) Gecko/20030324" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.2.1) Gecko/20021204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1; aggregator:NewsMonster; http://www.newsmonster.org/) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021213 Debian/1.2.1-2.bunk" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030124" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030225,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030327" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030502 Debian/1.2.1-9woody3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.2.1) Gecko/20021125" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.2.1) Gecko/20030228" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; ru-RU; rv:1.2.1) Gecko/20030721" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.2.1) Gecko/20030711" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; fr-FR; rv:1.2.1) Gecko/20030711" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (X11; U; Linux 2.6.13 i686; en-US; rv:1.2.9) Gecko/20050612 MSIE (Debian FAST Browser) v15.23 - All rights reserved - Unix -
Error Processing table...
Line 43
" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.3) Gecko/20030616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3a) Gecko/20021212" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3b) Gecko/20030210" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3; MultiZilla v1.4.0.3J) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3a) Gecko/20021212" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3b; MultiZilla v1.3.1 (a)) Gecko/20030210" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.3b) Gecko/20030323" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.3) Gecko/20030321" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.3) Gecko/20030313" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3a) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3b) Gecko/20030210" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030313" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030314" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030408" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030623" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030708 Debian/1.3-4.lindows43" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.3b) Gecko/20030317" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.3) Gecko/20030317" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.3a) Gecko/20021211" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.3) Gecko/20030314" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.3.1) Gecko/20030721 wamcom.org" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.3.1) Gecko/20030723 wamcom.org" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; el-gr; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.3.1) Gecko/20030524" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.3.1) Gecko/20030525" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.3.1) Gecko/20040413" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.3.1) Gecko/20040528" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3.1) Gecko/20030428" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3.1) Gecko/20030517" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.3.1) Gecko/20030428" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030507" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030529" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-us; rv:1.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4a) Gecko/20030401" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4b) Gecko/20030507" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030529" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030612" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.4) Gecko/20030624/7.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4a) Gecko/20030401" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030709" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030715" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030730" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20040127" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20040324" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.4) Gecko/20030730" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ca; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; da-DK; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4) Gecko/20030821" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4a) Gecko/20030401" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030507" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030529" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030617" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030703" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030704" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030714 Debian/1.4-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030716" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030728" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030730" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030805" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030807" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030818" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030821" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030908 Debian/1.4-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030915" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030922" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031110" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031112" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031119 Debian/1.4.0.x.1-20" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031211" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031212" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20040107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Larbin/2.6.3 (larbin@unspecified.mail)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Larbin/2.6.3 larbin@unspecified.mail" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.4) Gecko/20031111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; gl-ES; rv:1.4) Gecko/20030703" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.4) Gecko/20030922" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.4) Gecko/20030908" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenVMS AlphaServer_ES40; en-US; rv:1.4) Gecko/20030826 SWB/V1.4 (HP)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.4b) Gecko/20030523" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.4) Gecko/20040214" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.4) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4) Gecko/20030701" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4) Gecko/20031128" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4) Gecko/20040414" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-0; en-US; rv:1.4.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (MacOSX; U; MacOSX; en-US; rv:1.4.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.4.1) Gecko/20031014" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4.1; MultiZilla v1.5.0.2j) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031008 Debian/1.4-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031114 MSIE" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20040312 Debian/1.4.1-0jds1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20040406" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4.1) Gecko/20040406" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.4.1) Gecko/20031209" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4.1) Gecko/20031125" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4.2) Gecko/20040220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4.2) Gecko/20040301" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040301" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040323" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040326" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040330" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040428" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040921" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4.2) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4.2) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.4.2) Gecko/20040220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.4.3) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040924" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040930" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.4.3) Gecko/20040930" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.5b) Gecko/20030904" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.1" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.5) Gecko/20031007, Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; PL; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; fr-FR; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5a) Gecko/20030718" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20030916" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20030925" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5 ) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; PL; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.5) Gecko/20031006" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20030916" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20030925" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.5) Gecko/20031006" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; rv:1.5a; FreeBSD)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5a) Gecko/20030712" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5b) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031028" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20040102" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20040105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20040110" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20040921" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.5) Gecko/20031027" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.5) Gecko/20031015" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.5) Gecko/20031031" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.5) Gecko/20031107 Debian/1.5-3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030718" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030831" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20030917" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20030925" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031009" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031024" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031031" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Debian/1.5-3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Debian/1.5-3 StumbleUpon/1.906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031111 Debian/1.5-2.backports.org.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031115 Debian/1.5-3.he-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031202" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031211 Debian/1.5-2.0.0.lindows0.0.43.45+0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031224" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031231" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040225 Debian/1.5-2.0.0.lindows0.0.65.45+0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040414" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.5) Gecko/20031007 Debian/1.6-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5a) Gecko/20030723" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5) Gecko/20031016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5) Gecko/20031222" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5.1) Gecko/20031120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5.1) Gecko/20031207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040113 Relativity" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040206 MSIE/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6; lwpc5440) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; et-EE; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; hu; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; ja-JP; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; nl-NL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; cs-CZ; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6a) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6a) Gecko/20031105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 MSIE/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Poweranemone/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Powergoat/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Powerpig/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.6+) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nb-NO; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.6) Gecko/20040407" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-TW; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ar; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6a) Gecko/20020430" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6a) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 |sncwebguy|" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040119 MyIE2" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 GoogleBot/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 KPTX3/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Mozilla/5.0 StumbleUpon/1.904" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 msie/6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Spacedonkey/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Telnet/4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6; RattBrowser) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.6) Gecko/20040113,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; pt-BR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; DragonFly i386; en-US; rv:1.6) Gecko/20040518" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6a) Gecko/20031207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6a) Gecko/20040525" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040313" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040319" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040324" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040412" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040414" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040512" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; ru-RU; rv:1.6) Gecko/20040406" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.6) Gecko/20040122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040413" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040413 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040527" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040530 Debian/1.6-6.backports.org.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040216 Debian/1.6.x.1-10" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-IE; rv:1.6) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-IE; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6a) Gecko/20031029" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6a) Gecko/20031103" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6b) Gecko/20031113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6b) Gecko/20031210" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Fucking cocksmoker" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040112" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040119" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Debian/1.6-0.backports.org.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Debian/1.6-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Debian Sarge" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040123" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040124" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040127" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040203" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 dufus/42" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-us; rv:1.6) Gecko/20040207 firefox/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 InterBank 4.32" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040211" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040215 MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040216 Debian/1.6.x.1-10" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040223" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040224" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040229" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040303" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040306" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040307" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040310" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312 Debian/1.6-3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040314" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040318" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040321" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040324" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040325" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040326" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040329" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040330" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040401 Debian/1.6-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040402 Debian/1.6-3.backports.org.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040403" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040411" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040422" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040423" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040426 Debian/1.4-4 StumbleUpon/1.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040429" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040430" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040505" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040506" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040506 Powerstarfish/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040507" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040518" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040528 Debian/1.6-7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040530 Debian/1.6-6.backports.org.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6 kni-rat-sam 20041007) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6; Using IIS? Visit www.glowingplate.com/iis ) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040123 Debian/1.6-1.he-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040413 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040528 Debian/1.6-7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-CA; rv:1.6) Gecko/20040207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6b) Gecko/20031210" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040122 Debian/1.6-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040126" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040207 AnyBrowser /1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040413 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040429" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.6) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.6) Gecko/20040124" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.6) Gecko/20040122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.6) Gecko/20040528 Debian/1.6-7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.6) Gecko/20040331" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.6) Gecko/20040413 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.6) Gecko/20040122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.6) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux powerpc; en-US; rv:1.6) Gecko/20040207 FireFox/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.6) Gecko/20040414 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; eo-EO; rv:1.6) Gecko/20040414 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.6) Gecko/20040114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.6) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.6) Gecko/20040405" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.6) Gecko/20040408" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040314" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040324" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040820" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040902" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.6) Gecko/20040117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6a) Gecko/20031125" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040211 Lightningyak/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; es-ES; rv:1.6) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (BMan; U; BManOS; bg-BG; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (en-AU; rv:1.7)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; de-AT; rv:1.7a) Gecko/20040225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7a) Gecko/20040219" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7b) Gecko/20040421 netscape7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7a) Gecko/20040219" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040320" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040321" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040323" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040401" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040404" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefrog/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 FireFox/0.9.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 MSIE/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040730 Googlebot/2.1/2.1" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7b+) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; hu-HU; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nl-NL; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7a) Gecko/20040123" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7a) Gecko/20040219" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040328" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040403" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040408" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040410" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040412" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040520 K-Meleon/0.8" + family: "K-Meleon" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Moonsnake/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Powersnake/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Powerwhale/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Pussyfag/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Spacebunny/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040616 WebWasher 3.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Moonlizard/0.9.1 (:w00t: to the world and the world :w00t:s back!)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)/0.9.1" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firepig/0.9.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Lightningspider/0.9.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Telnet/4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Ungawa/0.9.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Waterphoenix/0.9.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Webpony/0.8 ( polymorph)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Superlizard/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Superraccoon/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 XboxStore.com" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7a) Gecko/20031129" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; Slackware; Linux i686; en-US; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; AIX 0006FADF4C00; en-US; rv:1.7b) Gecko/20040318" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7b) Gecko/20040422" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7b) Gecko/20040429" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040612" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; ja-JP; rv:1.7) Gecko/20040705" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; de-AT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7) Gecko/20040619" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7) Gecko/20040724" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7) Gecko/20040803 Nevermind/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-CA; rv:1.7) Gecko/20040704" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-EU; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-EU; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-EU; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-UK; rv:1.7a) Gecko/20040105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7a) Gecko/20040218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040322" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040405" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040408" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040612" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040615 Lightningoyster/0.9 (Mozilla/4.0 (compatible; MSIE 6.0; WinNT; ATHMWWW1.1;))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040617" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040619" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040620" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040622" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040624 Debian/1.7-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Microsoft/IE" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Mozilla/4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040702" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040703" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040704 Debian/1.7-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040724" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040725" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040728" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040729" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Lightningslimemold/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040805 Googlebot/2.1" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040808 Powertiger/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040809" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040828 Seagoat/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7rc1) Gecko/20040527" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7) Gecko/20040617" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7) Gecko/20040627" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Mac OS; en-US; rv:1.7) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OSF1 alpha; en-US; rv:1.7) Gecko/20040708" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7b) Gecko/20040319" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7c) Gecko/" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040517" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040610" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040623" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040920" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.2 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.1) Gecko/20040707 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fi-FI; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.1) Gecko/20040707 WebWasher 3.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD 5.2.1 i686; en-US; rv:1.7.1+) Gecko/20020518" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.1) Gecko/20040724" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.1) Gecko/20040726" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040715" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040715 Debian/1.7.1-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040726 Debian/1.7.1-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040730" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040802 Debian/1.7.1-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; Athlon64; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; PL; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20040815" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20040816" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2;) Gecko/20020604 OLYMPIAKOS SFP" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040726" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040808" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040808 Debian/1.7.2-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040809" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040809 Debian/1.7.2-0woody1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040810 Debian" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040810 Debian/1.7.2-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040815" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040816" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040819" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040819 Debian/1.7.2-3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040820 Debian/1.4-3 StumbleUpon/1.79" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040820 Debian/1.7.2-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040825" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.2) Gecko/20040818" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.2) Gecko/20040829" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.2) Gecko/20040906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.2) Gecko/20040823" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; de-AT; rv:1.7.2) Gecko/20040906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.2) Gecko/20040813" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.2) Gecko/20040809" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.2) Gecko/20040810" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.2) Gecko/20040826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; cs-CZ; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.3) Gecko/20040910,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 IE/0.10" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 WebWasher 3.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 WaterDog/0.10.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040922" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.3) Gecko/20040914" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.3) Gecko/20040919" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040914" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040916" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040918" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040919" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040922" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040922 Debian/1.7.3-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040925" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040926" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041006" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041006 Debian/1.7.3-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Debian" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041013" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041020" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041026" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041027" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041108" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5 StumbleUpon/1.999" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; it-IT; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.3) Gecko/20040921" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.3) Gecko/20041022" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Slackware GNU/Linux i686; pl-PL; rv:1.7.3) Gecko/20040913 --==MOZILLA RULLEZ ;)==--" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.3) Gecko/20040919" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.4) Gecko/20040926" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; ja-JP; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; rv:1.7.5) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Refrozen.com/2.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; it-IT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7.5) Gecko/20041210 MSIE/5.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 google/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 IE/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 MSIE/1.0 (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 TheBlacksheepbrowser/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; ; Win98; en; rv:1.7.5) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.5) Gecko/20041213" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Windows" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041228 Fedora/1.7.5-2.home" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.7.5) Gecko/20041108 MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7rc1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a4) Gecko/20040927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a5) Gecko/20041122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040511" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.8a4) Gecko/20040930 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a) Gecko/20040425 `The Suite'" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040521" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a3) Gecko/20040817" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a5) Gecko/20041122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040420" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.8a2+) Gecko/20040524" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8a4) Gecko/20040927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040607" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040704" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040713" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040812" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040817" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a4) Gecko/20040923" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a5) Gecko/20041122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041201" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040417" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040419" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040420" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040423" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040427" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040502" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040511" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8a2) Gecko/20040715" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 IP30; en-US; rv:1.8)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040627" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040808" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a4) Gecko/20040927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041123" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040424" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040502" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8a3) Gecko/20040822" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8a4) Gecko/20040929" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X; MSIE Incompatible; SyNiX; es-AR; rv:1.8a2/s) Gecko/20040814" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (compatible; MSIE 6.0; X11; U; Linux i686; en-US; rv:2.5 P)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/3.0 (Compatible;Viking/1.8)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01Gold (Macintosh; I; 68K)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01Gold (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-GB; rv:1.0.2) Gecko/20020924 AOL/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.2) Gecko/20020924 AOL/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20030306 Camino/0.7" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5b) Gecko/20030917 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6a) Gecko/20031021 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6b) Gecko/20031205 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7a) Gecko/20040105 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7a) Gecko/20040110 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040403 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040404 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040405 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040416 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040425 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040428 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040511 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040518 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040623 Camino/0.8" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a2) Gecko/20040602 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a2) Gecko/20040607 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a2) Gecko/20040610 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a3) Gecko/20040804 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a3) Gecko/20040811 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041130 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041222 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040825 Camino/0.8.1" + family: "Camino" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040827 Camino/0.8.1" + family: "Camino" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041201 Camino/0.8.2" + family: "Camino" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040517 Camino/0.8b" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20021220 Chimera/0.6+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030630 Epiphany/1.0" + family: "Epiphany" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030821 Epiphany/1.0" + family: "Epiphany" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030630 Epiphany/1.0.1" + family: "Epiphany" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031114 Epiphany/1.0.4" + family: "Epiphany" + major: '1' + minor: '0' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031208 Epiphany/1.0.6" + family: "Epiphany" + major: '1' + minor: '0' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Epiphany/1.0.6" + family: "Epiphany" + major: '1' + minor: '0' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031229 Epiphany/1.0.6" + family: "Epiphany" + major: '1' + minor: '0' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040223 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040115 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040114 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040115 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040114 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040118 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040317 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040324 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040124 Epiphany/1.0.8" + family: "Epiphany" + major: '1' + minor: '0' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312 Epiphany/1.1.12" + family: "Epiphany" + major: '1' + minor: '1' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040415 Epiphany/1.1.12" + family: "Epiphany" + major: '1' + minor: '1' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040415 Epiphany/1.2.2" + family: "Epiphany" + major: '1' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040206 Epiphany/1.2.2" + family: "Epiphany" + major: '1' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040322 Epiphany/1.2.2" + family: "Epiphany" + major: '1' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040429 Epiphany/1.2.3" + family: "Epiphany" + major: '1' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040404 Epiphany/1.2.3" + family: "Epiphany" + major: '1' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Epiphany/1.2.4" + family: "Epiphany" + major: '1' + minor: '2' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040528 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040906 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040413 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.6) Gecko/20040414 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040628 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040624 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040625 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040404 Epiphany/1.2.6.90" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803 Epiphany/1.2.7" + family: "Epiphany" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040810 Epiphany/1.2.7" + family: "Epiphany" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040818 Epiphany/1.2.7" + family: "Epiphany" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040819 Epiphany/1.2.7" + family: "Epiphany" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040922 Epiphany/1.2.7" + family: "Epiphany" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20040821 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20041016 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040807 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040820 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Epiphany/1.3.0" + family: "Epiphany" + major: '1' + minor: '3' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041112 Epiphany/1.4.4" + family: "Epiphany" + major: '1' + minor: '4' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041020 Epiphany/1.4.4" + family: "Epiphany" + major: '1' + minor: '4' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041113 Epiphany/1.4.4" + family: "Epiphany" + major: '1' + minor: '4' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.3) Gecko/20041126 Epiphany/1.4.5" + family: "Epiphany" + major: '1' + minor: '4' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041116 Epiphany/1.4.6" + family: "Epiphany" + major: '1' + minor: '4' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030504 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030610 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4b) Gecko/20030623 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 IP30; en-US; rv:1.4b) Gecko/20030618 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030722 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Solaris Sparc; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4b) Gecko/20030517 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Idefix hic erat!; Fenestra 50a.Chr.n.; la; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5a) Gecko/20030801 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030801 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030811 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030905 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030912 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030918 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030821 Mozilla Firebird/0.6.1+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030910 Firebird/0.6.1+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.5a) Gecko/20030908 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5a) Gecko/20030729 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5) Gecko/20031026 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; cs-CZ; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6a) Gecko/20031002 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6a) Gecko/20031105 Firebird/0.7+ (aebrahim)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6b) Gecko/20031208 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6b) Gecko/20031216 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040114 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040429 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; fr; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031023 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031208 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20040415 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031015 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031110 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031120 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031215 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031225 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040114 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040120 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040130 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040201 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6a) Gecko/20030924 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6a) Gecko/20031012 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040116 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5) Gecko/20031020 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5) Gecko/20031202 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5) Gecko/20040114 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7a) Gecko/20040113 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7a) Gecko/20040210 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7a) Gecko/20040120 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7a) Gecko/20040129 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040410 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040409 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7a) Gecko/20040118 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7a) Gecko/20040210 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Firefox)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win64 (AMD64); en-US; Firefox" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040815 Lightningraccoon/0.9.1+ (All your Firefox 0.9.1+ are belong to Firesomething!)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040413 Waterdog/0.8.0+ (Firefox/#version# polymorph)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox_123/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.6) Gecko/20040210 Firesalamandre/0.8 (User Agent modifie grace a Firesomething. Telechargez Firefox en francais sur http://frenchmozilla.org/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux; en-US) Gecko/20040101 Firefox" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Firefox (Gecko)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla Dark Firefox" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (Windows;+U;+Windows; en-GB) Gecko Firefox" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.3) Gecko/20040925 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040908 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1 WebWasher 3.3" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040928 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10 StumbleUpon/1.996" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040911 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040928 Firefox/0.10 (MOOX M2)" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; rv:1.7.3) Gecko/20040914 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041011 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040911 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040914 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040919 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040923 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040924 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040928 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040929 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041003 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.7.3) Gecko/20040911 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (MacOS; U; Panther; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041103 Mozilla Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041109 Firefox/0.10.1 (MOOX M3)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7) Gecko/20040803 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1 (Firefox/0.10.1 rebrand: Mozilla Firesomething)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040930 Firefox/0.10.1 (MOOX M3)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20041006 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 (MOOX M3)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/0.10.1 (MOOX M2)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a5) Gecko/20041031 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040910 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040911 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 (ax)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Thunderchicken/0.10.1 (All your Firefox/0.10.1 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.3) Gecko/20041027 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; Slackware; Linux i686; Slackware; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 6.5; rv:1.7.3) Gecko/20041020 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040911 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040914 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040916 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040921 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040928 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 (Linux/GTK)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Firefox/Slackware-0.10.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041003 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041005 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041007 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041008 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041011 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041012 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041013 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041014 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041015 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041019 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041020 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041021 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041023 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041025 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041026 Firefox/0.10.1 (Debian package 0.10.1+1.0PR-4)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041028 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041031 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041103 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041106 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041110 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041119 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041123 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041202 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; rv:1.7.3) Gecko/20041022 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; rv:1.7.3) Gecko/20041020 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; rv:1.7.3) Gecko/20050220 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; rv:1.7.3) Gecko/20040916 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Linux) Firefox/0.3" + family: "Firefox" + major: '0' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20041122 Firefox/0.5.6+" + family: "Firefox" + major: '0' + minor: '5' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20041122 Firefox/0.5.6+" + family: "Firefox" + major: '0' + minor: '5' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.6 StumbleUpon/1.73" + family: "Firefox" + major: '0' + minor: '6' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040407 Firefox/0.6 StumbleUpon/1.66" + family: "Firefox" + major: '0' + minor: '6' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.6.1 StumbleUpon/1.89" + family: "Firefox" + major: '0' + minor: '6' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.6.1 StumbleUpon/1.87" + family: "Firefox" + major: '0' + minor: '6' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.6 StumbleUpon/1.902" + family: "Firefox" + major: '0' + minor: '6' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041116 Firefox/0.6.1 StumbleUpon/1.87" + family: "Firefox" + major: '0' + minor: '6' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050110 Firefox/0.6.1 StumbleUpon/1.8 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '0' + minor: '6' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20050101 Firefox/0.6.4" + family: "Firefox" + major: '0' + minor: '6' + patch: '4' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.7 StumbleUpon/1.901" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.7 StumbleUpon/1.902" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.7 StumbleUpon/1.904" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040310 Firefox/0.7 StumbleUpon/1.895" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.7 StumbleUpon/1.9" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040313 Firefox/0.7" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Firefox/0.7 StumbleUpon/1.9" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040809 Firefox/0.7 StumbleUpon/1.89" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.8 Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.7b) Gecko/20040410 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.7b) Gecko/20040412 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Linux) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Firefox/0.8; Win32) Gecko/20040206" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Linux; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.903" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040308 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040311 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040314 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040325 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040509 Firefox/0.8.0+ (MMx2000)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040519 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040531 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+ StumbleUpon/1.99" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a2) Gecko/20040616 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040417 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040501 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040503 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040510 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040513 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040517 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fr; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; rv:1.8a2) Gecko/20040522 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Njindonjs HR; en-US; rv:1.6) Gecko/20040206 Firefox/0.8)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.908" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7b) Gecko/20040304 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7b) Gecko/20040318 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040608 Moonbadger/0.8.0+ (All your Firefox/0.8.0+ are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a2) Gecko/20040525 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a) Gecko/20040504 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; it-IT; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; ja-JP; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pt-BR; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; ru-RU; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; fr; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8 (Firefox/0.8)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 (All your Firefox/0.8 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 (ax)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.904" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.905" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.908" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Moonbird/0.8 (Firefox/0.8 polymorph)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Superwolf/0.8 (All your Firefox/0.8 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040210 Firefox/0.8 (www.proxomitron.de)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.8 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7a) Gecko/20040218 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040226 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040304 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040320 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040404 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040414 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040417 Firefox/0.8.0+ (MozJF)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040524 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040605 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040608 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040608 Firefox 0.8+/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040613 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.8 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.8 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a1) Gecko/20040520 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040521 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040523 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040525 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040604 Firefox/0.8.0+ (stipe) (Proxomitron Naoko 4.51)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040608 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040421 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040422 Firefox/0.8.0+ (TierMann VC++Tools)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040427 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040504 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040507 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040510 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040511 Firefox/0.8.0+ (ax)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040512 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040518 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7b) Gecko/20040412 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7b) Gecko/20040302 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8 (Proud Firefox user - IE suckz)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.8a) Gecko/20040508 Firefox/0.8 Royal Oak (Mozilla)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-NZ; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firecow/0.8 (Firefox/0.8 Get over it!)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 (ax)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 - <>" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 (John Bokma, http://johnbokma.com/)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 MSIE 5" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.903" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.906" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.907 (All your Firefox/0.8 StumbleUpon/1.907 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.908" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Lightningdog/0.8 (All your Firefox/0.8 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Waterworm/0.8 (All your Firefox/0.8 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040210 Firefox/0.8 (Lohvarn)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040210 Firefox/0.8 (stipe)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.8 StumbleUpon/1.908" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7a) Gecko/20040221 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040302 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040310 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040313 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040315 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040318 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040321 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040321 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040321 Firefox/0.8.0+ (mmoy)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040322 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040323 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040324 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040326 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040327 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040329 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040330 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040331 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040331 Firefox/0.8.0+ (scragz)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040403 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040404 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040406 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040406 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040407 Firefox/0.8.0+ (djeter)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040408 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040408 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040409 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040410 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040411 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040412 Firefox/0.8.0+ (mmoy-O2-GL7-SSE2-crc32-quek01235)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040512 Firefox/0.8.0+ (MOOX)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040520 Firefox/0.8.0+ (MOOX-AV)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040521 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040521 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040523 Firefox/0.8.0+ (MOOX-AV)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040529 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040530 Firefox/0.8.0+ (Lohvarn)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040601 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040601 Firefox/0.8.0+ (MOOX-TK)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040607 Firefox/0.8.0+ (MOOX-AV)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040610 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Waternarwhal/0.8 (Firefox/0.8)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040629 Firefox/0.8 (MOOX-AV)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.8 Gumby" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.8 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.8 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a1) Gecko/20040520 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040521 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040522 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040522 Firefox/0.8.0+ (MOOX-TK)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040523 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040524 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040524 Firefox/0.8.0+ (BlueFyre)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040525 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040526 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040527 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040601 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040602 Firefox/0.8.0+ (bangbang023)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040605 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040710 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040807 Firefox/0.8 StumbleUpon/1.99" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040415 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040417 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040425 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040426 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040428 Firefox/0.8.0+ (dbright)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040430 Firefox/0.8.0+ (mmoy-O2-GL7-SSE2-crc32)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040502 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040502 Firefox/0.8.0+ (scragz)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040503 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040503 Firefox/0.8.0+ (mmoy-Pentium4a)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040504 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040505 Firefox/0.8.0+ (MOOX)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040507 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040512 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040516 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040517 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040518 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040518 Firefox/0.8.0+ (mmoy-2004-05-05-Pentium4b)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.6) Gecko/20040206 Firefox 0.8/0.8 (MSIE 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.906" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.6) Gecko/20040209 Firefox/0.8 (Oxs G7 SSE optimized)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.8 StumbleUpon/1.99" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040803 Firefox/0.8 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8a2) Gecko/20040601 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; cs-CZ; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040606 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; en-US; rv:1.6) Gecko/20040227 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040213 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040218 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040303 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040317 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040405 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040422 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040425 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040429 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040503 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040504 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040610 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040627 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040805 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040812 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; ja-JP; rv:1.6) Gecko/20040429 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040212 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040227 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040428 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040612 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.8a) Gecko/20040418 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040429 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040506 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-UK; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.8 StumbleUpon/1.904" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.8 StumbleUpon/1.99" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.8 TGB579860FilterStats" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040208 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040209 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040211 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040212 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040216 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040220 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040221 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040222 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040223 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040224 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040226 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040227 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040228 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040229 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040301 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040301 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040302 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040308 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040310 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040316 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040317 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040317 Firefox/0.8 - www.ubuntulinux.org" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040322 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040323 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040324 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040327 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040330 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040402 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040403 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040404 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040405 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040405 Firefox/0.8.0+ StumbleUpon/1.895" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040407 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040412 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040415 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040416 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040417 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040418 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040420 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040421 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040422 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040423 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040424 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040425 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040426 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040427 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040428 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040429 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040501 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040502 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040503 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040504 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040506 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040508 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040509 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040513 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040514 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040515 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040517 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040518 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040519 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040522 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040523 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040527 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040530 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040531 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040602 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040611 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040612 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040621 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040630 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040701 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040713 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040715 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040726 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.8 StumbleUpon/1.904" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.8 StumbleUpon/1.906" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Firefox/0.8 (Debian package 1.0-4)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050110 Firefox/0.8 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7a) Gecko/20040218 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/02004032 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040313 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040326 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040328 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040403 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040411 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040630 Firefox/0.8 StumbleUpon/1.904" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040708 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040529 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040602 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040605 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040617 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040630 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040428 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040429 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040430 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040502 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040503 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040505 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040516 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040518 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040225 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040327 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040506 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040602 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040219 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040327 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040421 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040506 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040602 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; MS-is-evil; en-US; rv:1.6) Gecko/20040405 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.6) Gecko/20040219 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sl-SI; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sl-SI; rv:1.6) Gecko/20040212 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.6) Gecko/20040602 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.6) Gecko/20040327 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.6) Gecko/20040603 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.6) Gecko/20040615 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.6) Gecko/20040527 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.6) Gecko/20040408 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.6) Gecko/20040609 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040324 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040825 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040902 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20041228 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20050204 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20050228 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD macppc; en-US; rv:1.6) Gecko/20040822 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040211 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040214 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040403 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040629 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/6.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040222 Firefox/0.8.0+ (mmoy)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040604 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040628 Firefox/0.9.1 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040614 Firefox/0.9 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040815 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.7) Gecko/20040614 Firefox/0.9 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041107 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.9 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Lightningdog/0.9 (Firefox/0.9 polymorph)" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040617 Firefox/0.9.0+" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040711 Firefox/0.9.0+" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.3 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Firefox/0.9 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 Firefox/0.9.0" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.9 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.9 WebWasher 3.3" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 INTERNET COMMANDER/0.9 (All your Firefox/0.9 are DEREK SMART'S BECAUSE HE HAS A PHD AND YOU DON'T)" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040623 Firefox/0.9.0+" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040625 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040703 Firefox/0.9.0+" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.0" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040808 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.9 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040629 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040615 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040615 Firefox/0.9 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040615 Seaant/0.9 (All your Firefox/0.9 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040616 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040617 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040619 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040620 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040624 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040701 Firefox/0.9.0+ (daihard: P4/SSE2)" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040704 Firefox/0.9.0+" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7) Gecko/20040616 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040615 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040616 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "UserAgent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.3) Gecko/20040831 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040628 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a3) Gecko/20040810 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a5) Gecko/20041121 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.7) Gecko/20040629 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.2) Gecko/20040819 Firefox/0.9.1+ (ax)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040713 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8a6) Gecko/20041127 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040811 Firefox/0.9.1+ (pigfoot)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.1 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040804 Firefox/0.9.1+ (bangbang023)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040808 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a3) Gecko/20040815 Firefox/0.9.1+ (MOOX-TK)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a5) Gecko/20041110 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040810 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040811 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040812 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040814 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040814 Firefox/0.9.1+ (MOOX M3)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20040629 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.1 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.1 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Spacepanda/0.9.1 (Firefox/0.9.1 serious edition)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040729 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040802 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040802 Firefox/0.9.1+ (moox)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040805 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040726 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040811 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040820 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040827 Firefox/0.9.1+ (MOOX M3)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040901 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040904 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a5) Gecko/20041114 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040629 Firefox/0.9.1 (MOOX-AV)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; it-IT; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win NT 5.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040706 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040725 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040729 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040804 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040806 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7) Gecko/20040629 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; pt-BR; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040819 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040825 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040629 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040630 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040701 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040702 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040704 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040705 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040706 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040708 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040710 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040711 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040714 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040715 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040719 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040721 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040729 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040730 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040730 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040801 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040802 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.1+ (lokean SVG-enabled)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040804 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040730 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040805 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040824 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040902 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041027 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7) Gecko/20040712 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7) Gecko/20040719 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040629 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Firefox 0.9.2 (The intelligent alternative)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.7) Gecko/20040711 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pt-BR; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2 (ax)" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pt-BR; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2 (ax)" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Waterbug/0.9.2 (All your Firefox/0.9.2 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040709 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040708 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040712 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040716 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040801 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040802 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Firefox 0.9.3 (compatible;MSIE 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Firefox/0.9.3 (compatible;MSIE 6.1; Windows 98)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Firefox 0.9.3 (compatible MSIE is gay;Linux)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Firefox/0.9.3 [en] (All your base are belong to us)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (i686; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; it-IT; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3 (#)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 WebWasher 3.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firejackalope/0.9.3 (All your Firefox/0.9.3 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040805 Firefox/0.9.3 (djeter)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fr; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD amd64; en-US; rv:1.7) Gecko/20041015 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040806 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040807 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040811 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040813 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040830 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040910 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040927 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20041016 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7) Gecko/20040808 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ca-CA; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7) Gecko/20040809 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040804 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040805 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040806 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040807 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040808 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040809 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040810 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040813 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040814 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040818 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040819 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040823 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040824 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040825 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040827 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040830 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040831 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040901 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040904 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040914 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040917 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040920 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040926 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040928 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu) StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; uk-UA; rv:1.7) Gecko/20040809 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; de-DE; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7) Gecko/20040813 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; fr; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7) Gecko/20040902 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7) Gecko/20040817 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; WinNT; es-AR; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20050302 Firefox/0.9.6" + family: "Firefox" + major: '0' + minor: '9' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.6" + family: "Firefox" + major: '0' + minor: '9' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050302 Firefox/0.9.6" + family: "Firefox" + major: '0' + minor: '9' + patch: '6' + - user_agent_string: "Best website about travels.(New Zealand, Thailand, Bolivia)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "appName/appVersion (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.5) Gecko/20041107 Firefox/1.0 (vendorComment)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "(Firefox/1.0; Mac OS X Panther)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Firefox/1.0 Mozilla/5.0 Netscape/7.1elezeta (Debian GNU/Linux)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.17; Mac_PowerPC) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.001 (Windows NT 5.0) [en] Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Amiga OS; U; Amiga OS 5.3; en-US; rv:5.3) Gecko/20040707 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (ca-AD; Celtric) Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; ; Apple ][) Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Gameboy Color; U; Gameboy OS 2005; de-DE) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Linux; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Linux i686; nb-NO; rv:1.7.5) Gecko/20041108 Firefox/1.0 Frodo" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Linux; U; Windows NT 5.1; es-ES; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2 (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0 (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041130 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040628 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041207 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041211 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041222 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041225 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20050109 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050220 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050224 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050225 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050128 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050128 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050202 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050205 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050209 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050212 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050216 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050217 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050218 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; ja-JPM; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; ja-JPM; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (; U;;; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; de-DE;SKC) Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 Windows Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; de-AT; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; ja-JP; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; cs-CZ; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; da-DK; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; el-GR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.7.5) Gecko/20041113 Firefox/1.0 (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (*mh*)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 SR" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a6) Gecko/20050108 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a6) Gecko/20050110 Firefox/1.0+ (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b2) Gecko/20050302 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b) Gecko/20050115 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b) Gecko/20050218 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; hu-HU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; hu-HU; rv:1.7.5) Gecko/20041110 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; ja-JP; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pt-BR; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; tr-TR; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; zh-CN; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows 98; nl-NL; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ca-AD; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; cs-CZ; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; da-DK; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; da-DK; rv:1.7.5) Gecko/20041118 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/~20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0 WebWasher 3.3" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 -awstats-exclude" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 Mnenhy/0.6.0.104" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 PR" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.998" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041115 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041123 Firefox/1.0 (Community Edition FireFox P4W-X2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20050114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5; Google-TR-1) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040812 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20041209 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050101 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050107 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6; Google-TR-1) Gecko/20050101 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050301 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050117 Firefox/1.0+ (BlueFyre)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050118 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050122 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050131 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050201 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050202 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050204 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050206 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050206 Firefox/1.0+ (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050209 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050210 Firefox/1.0+ (BlueFyre)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050215 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; hu-HU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ko-KR; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nl-NL; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; sl-SI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.3) Gecko/20041101 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.5) Gecko/20041124 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; bg-BG; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ca-AD; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-bn; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 Mnenhy/0.6.0.104" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 WebWasher/1.2.2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0 (CK-UKL)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0 StumbleUpon/1.999,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; el-GR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-AU; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.8b2) Gecko/20050226 Firefox/1.0+ (nightly)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.8b) Gecko/20050216 Firefox/1.0+ (trunk)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-EN; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-gb; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0 StumbleUpon/1.9992" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041113 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041129 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-NZ; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-UK; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040903 Firefox/1.0 PR (NOT FINAL) (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041106 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 Ad/www.yetanotherblog.de" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (All your Firefox/1.0 are belong to us)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (Arjan says HI!)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (Goobergunchian Edition)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 Mnenhy/0.6.0.104" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 Mnenhy/0.7.1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (Not Netscape 7.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 sexyfox/0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.9992" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 WebWasher 3.3" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 www.city.poznan.pl/1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Superjellyfish/1.0 (All your Firefox/1.0 are belong to Firesomething)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M3) Mnenhy/0.6.0.104" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 StumbleUpon/1.999 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 StumbleUpon/1.999 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041112 Firefox/1.0 (stipe)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041115 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050129 Firefox/1.0 (pigfoot)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050206 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050209 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050211 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050214 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5; Google-TR-1) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5; Google-TR-1) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5;ME) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0 StumbleUpon/1.9992" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20040103 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041204 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041206 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041209 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041211 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041214 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041215 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041218 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041220 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041221 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041229 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041230 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050101 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050104 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050108 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050109 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050111 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050131 Firefox/1.0+ (Firefox CE Trunk 2004-12-23 P4W-X15)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050222 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050301 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050305 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050113 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050115 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050116 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050117 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050118 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050123 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050124 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050125 Firefox/1.0+ WebWasher 3.3" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050126 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050128 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050131 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050201 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050204 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050205 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050206 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050207 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050210 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050211 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050213 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050215 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050216 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050217 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050218 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0; ortzzuwt" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041107 xFirefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041210 Firefox/1.0 Internet Watcher 2000/ V1.4" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5; Google-TR-1) Gecko/20041109 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu-HU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041108 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041108 Firefox/1.0 StumbleUpon/1.996" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-VE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.5) Gecko/20041111 Firefox/1.0 (JTw)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.8a6) Gecko/20050107 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ko-KR; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.5) Gecko/20041116 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7.5) Gecko/20041110 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.8a6) Gecko/20050109 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.8b2) Gecko/20050220 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.8b) Gecko/20050206 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.8b) Gecko/20050218 Firefox/1.0+ (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ro-RO; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sk-SK; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sl-SI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sl-SI; rv:1.7.5) Gecko/20041113 Firefox/1.0 (largie's)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.5) Gecko/20040321 Firefox/1.0 DEBUG" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.7.5) Gecko/20041124 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8a6) Gecko/20050110 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8b2) Gecko/20050228 Firefox/1.0+ (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8b) Gecko/20050114 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; es-es; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; ru-RU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 6.0; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; ; Windows NT 5.1; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Slackware - current; Linux i686; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Slackware; Linux i586; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Darwin Power Macintosh; en-US; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD amd64; en-US; rv:1.7.3) Gecko/20041104 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD amd64; en-US; rv:1.7.5) Gecko/20050104 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-UK; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041029 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041113 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041115 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041120 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041123 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041125 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041127 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041130 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041203 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041209 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041215 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041218 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041222 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041224 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041227 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041228 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041229 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050102 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050104 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050105 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050106 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050115 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050117 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050120 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050123 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050125 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050127 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050204 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050205 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050212 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050215 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050225 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050226 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; ja-JP; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i686; es; rv:1.7.5) Gecko/20041128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux) Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0 (Debian package 1.0-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20050103 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; chrome://navigator/locale/navigator.properties; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041119 Firefox/1.0 (Debian package 1.0-3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20050206 Firefox/1.0 (Debian package 1.0+dfsg.1-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-CH; rv:1.7.5) Gecko/20040107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041111 Firefox/1.0 (Debian package 1.0-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041207 Firefox/1.0 (Debian package 1.0-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041211 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20050202 Firefox/1.0 (Debian package 1.0+dfsg.1-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.5) Gecko/20041209 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu4-warty99)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8) Gecko/20050101 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040907 Firefox/1.0 PR (NOT FINAL)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041029 Firefox/1.0RC1 (Debian package 0.99+1.0RC1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041030 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041030 Firefox/1.0RC1 (Debian package 0.99+1.0RC1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041102 Firefox/1.0RC1 (Debian package 0.99+1.0RC1-3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041105 Firefox/1.0RC1 (Debian package 0.99+1.0RC1-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041112 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041009 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041106 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0 (Debian package 1.0-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0 SPELLSHIDO!" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041113 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041115 Firefox/1.0 StumbleUpon/1.998" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041116 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041116 Firefox/1.0 (Ubuntu) StumbleUpon/1.999 (Ubuntu package 1.0-2ubuntu3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041116 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041117 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041117 Firefox/1.0 (Debian package 1.0-2.0.0.45.linspire0.4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041119 Firefox/1.0 (Debian package 1.0-3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041120 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041120 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041121 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041123 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041125 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041126 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041127 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 0.99+1.0RC1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041129 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041129 Firefox/1.0 (Debian package 1.0-3.backports.org.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041130 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041201 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041203 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041204 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041204 Firefox/1.0 (Debian package 1.0.x.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041205 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041206 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041207 Firefox/1.0 (Debian package 1.0-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041207 Firefox/1.0 StumbleUpon/1.999 (Debian package 1.0-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041208 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041209 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041209 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu4-warty99)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041211 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041212 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041213 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041214 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041214 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041215 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041215 Firefox/1.0 Red Hat/1.0-12.EL4" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041216 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041218 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041219 Firebunny/1.0 (Firefox/1.0)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041219 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041219 Firefox/1.0 (Debian package 1.0+dfsg.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041219 Firefox/1.0 (Debian package 1.0+dfsg.1-1) Mnenhy/0.7.1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041220 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041222 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041223 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041223 Firefox/1.0 Yoper/FIREFOX_RPM_AM" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041224 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041225 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041226 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041227 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041228 Firefox/1.0 Fedora/1.0-7" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041228 Firefox/1.0 Fedora/1.0-8" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041230 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041231 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050103 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050104 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050106 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050109 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050113 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050115 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050116 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050120 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050120 Firefox/1.0 (Debian package 1.0+dfsg.1-3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050121 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050121 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050123 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050123 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050125 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050126 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050127 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Debian package 1.0.x.2-13)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050129 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050130 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050131 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050201 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050202 Firefox/1.0 (Debian package 1.0+dfsg.1-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050203 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050203 Firefox/1.0 (Debian)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050203 Firefox/1.0 (Debian package 1.0.x.2-15)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050205 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050206 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050206 Firefox/1.0 (Debian package 1.0+dfsg.1-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050209 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0 StumbleUpon/1.999 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050215 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050218 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050222 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050223 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050225 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050228 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20041013 Firefox/1.0.0" + family: "Firefox" + major: '1' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a6) Gecko/20041204 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050117 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050201 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050207 Firefox/1.0+ (daihard: P4/SSE2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050212 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050218 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-MX; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0 Mnenhy/0.7" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20041115 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20041116 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20041119 Firefox/1.0 (Debian package 1.0-3 Moostik.net)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050110 Firefox/1.0 StumbleUpon/1.998 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050202 Firefox/1.0 (Debian package 1.0+dfsg.1-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050206 Firefox/1.0 (Debian package 1.0+dfsg.1-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; he-IL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hr-HR; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.7.3) Gecko/20041101 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20041108 Slackware Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20050110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.5) Gecko/20050110 Firefox/1.0 StumbleUpon/1.999 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; tr-TR; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; us; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i786; en-US; rv:1.8b2) Gecko/20050225 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i786; en-US; rv:1.8b) Gecko/20050212 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20041116 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20041125 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20041209 Firefox/1.0 (Debian package 1.0-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20041220 Firefox/1.0 (Debian package 1.0+dfsg.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050123 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; es-US; rv:1.7.5) Gecko/20041220 Firefox/1.0 (1.0)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux; sl-SI; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; da-DK; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041112 Firefox/1.0 (Debian package 1.0-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041116 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041117 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041130 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041204 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041214 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041218 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041226 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050104 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050106 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050111 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050211 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; MSIE 6.0; Linux i686; en-US; rv:1.7.5; IDF-BCC;) Gecko/20041111 Firefox/1.0 (Debian package 1.0-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.5) Gecko/20041114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.5) Gecko/20050103 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.5) Gecko/20050126 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD amd64; en-US; rv:1.7.5) Gecko/20050122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.7.5) Gecko/20041128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.7.5) Gecko/20050101 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Slackware; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Slackware; Linux i686; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7.5) Gecko/20041213 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7.5) Gecko/20050101 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20041130 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20041207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20050213 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "WhoreNuts/2.0 (Windows; U; Win98; en-US; rv:1.7.5) ScabCount/123883 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Gecko/20041108 Firefox/1.0; Mac_PowerPC)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Gecko/20050225 Firefox/1.0.1 Antares; U; Antares 5.5" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Gecko/20050228 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050227 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; hu-HU; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; nl-NL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050222 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050224 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 robert" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 StumbleUpon/1.9992" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1 (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ca-AD; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; el-GR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 StumbleUpon/1.9992" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050224 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050224 Firefox/1.0.1 (pigfoot)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6; Google-TR-1) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu-HU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.6) Gecko/20050301 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.7.6) Gecko/20050301 Firefox/1.0.1 Fedora/1.0.1-1.3.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050224 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050224 Firefox/1.0.1 Fedora/1.0.1-1.3.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Red Hat/1.0.1-1.4.3" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050227 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050301 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050301 Firefox/1.0.1 (Debian package 1.0.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050302 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050302 Firefox/1.0.1 Fedora/1.0.1-1.3.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050305 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.6) Gecko/20050301 Firefox/1.0.1 (Debian package 1.0.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.6) Gecko/20050224 Firefox/1.0.1 Fedora/1.0.1-1.3.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050302 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050225 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.3) Gecko/20041101 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20041030 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20041031 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20041101 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041102 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041105 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Linux Slackware; U;Linux Slackware 10.1; en-US; rv:1.8.0) Gecko/20050616 Firefox/1.1" + family: "Firefox" + major: '1' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0) Gecko/20050304 Firefox/1.1" + family: "Firefox" + major: '1' + minor: '1' + patch: + - user_agent_string: "Mozilla Firefox/5.0" + family: "Firefox" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/7.1" + family: "Firefox" + major: '7' + minor: '1' + patch: + - user_agent_string: "Firefox 7.1.3(compatible MSIE is gay;Linugz)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Linux Slackware x86_64 BlackBox; de_AT; Intel@Xeon) Firefox/Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.2b) Gecko/20021016 K-Meleon 0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20021016 K-Meleon 0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8" + family: "K-Meleon" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.1" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 MultiZilla/ StumbleUpon/1.995" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040613 MultiZilla/1.5.0.4h" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.7) Gecko/20040617 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.8a3) Gecko/20040819 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.2) Gecko/20040804 MultiZilla/1.6.4.0b (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3.1; MultiZilla v1.4.0.3J) Gecko/20031007 MultiZilla/1.6.0.0d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6a) Gecko/20031030 MultiZilla/1.6.0.0a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.0.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040316 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040316 MultiZilla/1.6.3.1c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040318 MultiZilla/1.6.1.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040514 MultiZilla/1.6.4.0a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040616 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7) Gecko/20040616 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.0.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.3.0d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.3.1c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.1) Gecko/20040707 MultiZilla/1.6.3.2c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.1) Gecko/20040707 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 MultiZilla/1.6.2.0c (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 MultiZilla/1.6.4.0b (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.6.0.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040421 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040514 MultiZilla/1.6.3.2f" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040514 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040616 MultiZilla/1.6.2.1a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040616 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a1) Gecko/20040520 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040714 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a4) Gecko/20040927 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040429 MultiZilla/1.6.3.2c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.4) Gecko/20030624 MultiZilla/1.6.1.0b (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Debian GNU/Linux - only dead fish go with the flow - i686; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040301 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115 MultiZilla/1.6.2.1a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115 MultiZilla/1.6.3.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040528 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040913 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041014 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040316 MultiZilla/1.6.3.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040421 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040425 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040608 MultiZilla/1.6.2.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040618 MultiZilla/1.6.2.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040805 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040501 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 MultiZilla/v1.1.20" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2b) Gecko/20021007 Phoenix/0.3" + family: "Phoenix" + major: '0' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5" + family: "Phoenix" + major: '0' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5" + family: "Phoenix" + major: '0' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5" + family: "Phoenix" + major: '0' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MS FrontPage 6.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MSFrontPage/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.0; Windows 3.1)" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.0; Windows 3.1; Sculptor; Rules)" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.0; Windows 95)" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.0; Windows 95) via HTTP/1.0 coder.internet-elite.com/" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/3.0 (compatible; MSIE 3.0; Windows NT 5.0)" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.01; Windows 3.1)" + family: "IE" + major: '3' + minor: '01' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.01; Windows 95)" + family: "IE" + major: '3' + minor: '01' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.02; Windows 95)" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.02; WindowsCE" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; PIEPlus 1.2; 240x320; PPC)" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; PPC; 240x320)" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; Smartphone; 176x220)" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; MSN 2.5; Windows 95)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows 95)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows 95; FunWebProducts-MyWay)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows 95; .NET CLR 1.1.4322)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows NT)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows NT 4.0)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows NT 5.0)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows NT 5.1)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows XP)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; AOL 4.0; Mac_PPC)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; AOL 4.0; Windows 95; Toshiba Corporation)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; AOL 5.0; Mac_PPC)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Mac_PowerPC)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; MSN 2.5; AOL 3.0; Windows 98; Compaq; wGoVols)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; MSN 2.5; MSN 2.5; AOL 4.0; Windows 98)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; MSN 2.5; Windows 98)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 2000)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95; FREESERVE_IE4)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95; iOpus-I-M)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95; QXW0300f)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95; TriStar Enterprises)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98;CP=MS)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98; DigExt)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98; DT)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98; Messages.co.uk)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; 240x320)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; MSN Companion 2.0; 800x600; Compaq)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; Smartphone; 176x220)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows; U; 32bit)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.5; Mac_PowerPC)" + family: "IE" + major: '4' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.5; Windows 98; )" + family: "IE" + major: '4' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.5; Windows NT 5.0)" + family: "IE" + major: '4' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5; Windows NT 5.1; Windows XP SP2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.00; Windows 98" + family: "IE" + major: '5' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 4.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 5.0; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 5.0; Windows 95; DigExt; DT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 5.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 5.0; Windows 98; DigExt; DT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 6.0; Windows 98; Compaq; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 6.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0;TargetAOL7.0; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0;TargetAOL7.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0; Windows 98)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0; Windows 98; DigExt; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0; Windows 98; Hotbar 4.3.2.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 8.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0b1; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; AtHome021)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; e412357VZ_IE50M)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; p412360OptusCabl)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; s412454BPH6mac)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; s412514Mac/m/4.5)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; S425166QXM03307)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC) (via translate.google.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; X111923v13b.08)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.0; AOL 7.0; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.5; AOL 5.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.5; AOL 5.0; Windows 98; DT; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.5; MSN 2.5; Windows 98)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.5; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.5; Windows 98; DigExt; CindyKlett 1)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSNIA; AOL 7.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; AT&T WNS5.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; BTinternet V8.4; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; 1.21.2 )" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; AtHome0107)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; btclick.com Build BTCFSOHOQ2)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; DT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; freenet 4.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; Hotbar 2.0; AT&T CSM6.0; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; JUNO)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; LILLY-EMA-EN)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; QXW0330q)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; QXW03314)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; sureseeker.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; tco2)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; YComp 5.0.2.4)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DT; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; OZEMR1999V01)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95) VoilaBot BETA 1.2 (http://www.voila.com/)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; ZDNetSL)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; {10708F41-46D9-11D9-9941-0008A127FF36})" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; {251744E0-8FEE-11D8-8ED7-00045A9E19B3})" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; {BD767A21-2BDF-11D9-B494-0050BAFA5FC2})" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Compaq; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Compaq; DigExt; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0(compatible; MSIE 5.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; A084)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; AIRF)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Arcor 2.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; AtHome033; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Creative)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; */E-Plus-002)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; freenet200)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; freenet 4.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; FreeSurf myweb.nl v1.0.1)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; FunWebProducts; Creative)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; FunWebProducts; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Hotbar 2.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Hotbar 4.3.2.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Hotbar 4.3.5.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; iebar)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt);JTB:15:88fba442-193e-11d9-bb86-0050fc8126b1" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; KITL27; (R1 1.3))" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; LanguageForce)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Mannesmann Arcor)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Matrix Y2K - Preview Browser)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MAX1.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MCNON1.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MindSpring Internet Services)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc21; v5m)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MSN 6.1; MSNbMSFT; MSNmen-us; MSNczz; v5m)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MSNIA)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; pbc4.0.0.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; pi 3.0.0.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; QXW0331m)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; QXW0331w)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; (R1 1.3))" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; SC/5.07/1.00/Compaq)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; searchengine2000.com; sureseeker.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; StudentenNet)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; sureseeker.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; TencentTraveler )" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; TiscaliFreeNet)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; tn3.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; V1.0Tomorrow1000)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt) via Avirt Gateway Server v4.2" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Virgilio3pc)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; VNIE5 RefIE5)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; vtown v1.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; www.ASPSimply.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; YComp 5.0.2.4)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; YComp 5.0.2.5)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; YComp 5.0.2.6)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; yplus 1.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; formatpb; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; FunWebProducts; Hotbar 4.4.5.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; NETACT; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; provided by VSNL)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Q321120)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; QXW03301; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; QXW03301; DigExt; sunrise4)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Software Trading Edition)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; WebHopper)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; YComp 5.0.0.0; Cox High Speed Internet Customer; sbcydsl 3.12" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows ME)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT;)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.1)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; Bob)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; Adam's Mark Hotels)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; AT&T WNS5.0; AT&T CSM6.0; AT&T WNS5.0 IE5.0.01)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; DT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; DTS Agent" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; (R1 1.3))" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; TBIT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; Yahoo-1.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DT; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; QXW0330d; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 [fi] (compatible; MSIE 5.0; Windows 98)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 [fr] (compatible; MSIE 5.0; Windows 98)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.0; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.0; Windows 98;)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.0; Windows NT/95/98))" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "MSIE 5.0" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "MSIE 5.0 (compatible; noyb; Windows5.1)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 4.0; Windows 98)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 4.0; Windows 98; QXW0332b)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 5.0; Windows 95; QXW0332b)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 7.0; Windows 98)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 7.0; Windows 98; YPC 3.0.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 8.0; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; CS 2000; Windows 95; AT&T WNS5.0; DigExt)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; MSN 2.5; Windows 98)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; MSNIA; Windows 95; MSNIA)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; BCD2000; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; DT)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; Microplex 1.0.1.5; OptusIE501-018)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; Microplex 2.0; OptusIE501-018)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSNIA)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; QXW0332b)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; QXW0332i)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; QXW03336)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; QXW0333a)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; SEARCHALOT.COM IE5; iOpus-I-M)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; USA On-Site)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; Xtra)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; 1012SurfnetVersion2.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; 1&1 Puretec)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; 981)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; AO1.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; AskBar 2.01; Hotbar 4.4.5.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; BCD2000)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; BPH32_57a)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; BT Internet)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Config C)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; DT)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; F-5.0.1SP1-20000718; F-5.0.1-20000221)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; FDM)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Feat Ext 19)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; FREE)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; FunWebProducts; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; GTE_IE5)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar 2.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar 3.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar 4.4.2.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar 4.4.7.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar 4.5.1.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar4.5.3.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; KSC)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.0.6; InterDigital-T]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.4.2; i-Player; netbox; NetgemUK]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.4.3b1; i-Player; netbox; NetgemUK]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.5.2a; i-Player; netbox; btdigitaltv]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.5.2a; i-Player; netbox; NetgemUK]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.5.2b; i-Player; netbox; NetgemUK]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; MRA 2.5 (build 00387))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; MSNIA)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; MSOCD; AtHome020)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; OptusIE501-018)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; pi 3.0.0.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; QXC03304)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; QXW03335)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; QXW03336)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; (R1 1.3))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; SEARCHALOT.COM IE5)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; SPINWAY.COM)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; SQSW)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; sureseeker.com)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; surfEU DE S1)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Teleos)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; TNET5.0NL)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; {World Online})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; YComp 5.0.2.6)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 4.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {2BBC0D6A-BD8E-43C8-9CA1-81673682EF32})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {31BF9C41-DE4C-49B8-B050-19E27C86DC76})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {59C0EB25-1B95-4B4C-AF0B-C247D74597B0})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {87CA9FD1-DEE6-4CB5-98FE-62BA2CA583DE})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {944D8EEF-056A-4073-B8F3-C317B94BA3C0})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {A68BF0C3-9B5E-4F63-A05B-0ADCAF21F0C8})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {ABF22706-058D-48D2-B032-BC3A65229618})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Admiral Group Limited -)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; AHP)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Assistant 1.0.2.4)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; AtHome021SI)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Bitscape Solutions, India)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Boeing Kit)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {CDC8EB20-F4B7-4407-BD64-40AB1B97D85C})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Coles Myer Ltd.)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Creative)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; DigExt)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; DigExt; iebar; (R1 1.5))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; DigExt; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; DigExt; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; digit_may2002)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; DT)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {E73D9CB8-6F87-458B-9943-F0284A59F969}; FDM)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {EEC83506-405F-4B48-BA4F-047A5AA92F3E})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; */E-Plus-002)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; F-5.0.1-20021031)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FDM)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FPC 014)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts-MyTotalSearch)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts; .NET CLR 2.0.40607)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FW1)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; H010818)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)Host: www.pgts.com.au" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 3.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 3.0) via NetCache version 3.1.2c-Solaris" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.2.4.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.3.1.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.4.2.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.4.5.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.4.5.0; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar4.5.3.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; i-NavFourF)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; iOpus-I-M)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Launceston Church Grammar School)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Mohammad Ali Jinnah University)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; MRA 4.0 (build 00768))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; MSOCD; AtHome020)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 1.0.2914)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 2.0.40607)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Netcom_BA_DD)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; OptusIE55-31)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; PCUser)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; PhaseOut-www.phaseout.net; PhaseOut-www.phaseout.net)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Q312461)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Q321120)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Q321120; Feat Ext 20)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; (R1 1.1))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; (R1 1.3))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; (R1 1.5))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Sgrunt|V106|671|S-1000478620)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Smart Explorer 6.1)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; surfEU DE M2)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; T312461)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; TencentTraveler )" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; TNT Australia Pty Ltd)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; T-Online Internatinal AG; MSIECrawler)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; WebTap)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; YComp 5.0.2.5)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; YComp 5.0.2.6; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.1)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; Aztec)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; BWB 09032000; BWB 07032000)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; DT)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; freenet 4.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; IE4SUPER; IE4COPLEY; proxyho; proxyinternet)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; IE501NTAb)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; OIZ - Switzerland)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; QXW0332s)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; QXW03336)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; [R1 1.3])" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; SBC)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; Sears Roebuck and Co. 2001)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; S.N.O.W Workstation)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; v1.0 C1; v2.0 C3; v4.0 C3; v2.0 C1)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; v1.0 C1; v4.0 C3)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; www.k2pdf.com)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; YComp 5.0.2.4)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "MSIE 5.01" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "MSIE 5.01 (Windows 98)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.05; Windows NT 4.0)" + family: "IE" + major: '5' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.05; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.12; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.13; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '13' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.14; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '14' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.15; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '15' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.16; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '16' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.17; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '17' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.17; Mac_PowerPC),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '17' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.2; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '2' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.2; Mac_PowerPC) - Internet Explorer 5.2, Mac" + family: "IE" + major: '5' + minor: '2' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.21; Mac_PowerPC" + family: "IE" + major: '5' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.21; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.22; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 95)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 95; Arcor 2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 95; EWE TEL)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 95; FDM)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98; VV50110)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98; Win 9x 4.90; Q312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0;TargetAOL6.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0; Windows 95)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 95)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; {326AFFA0-90D0-11D8-9D83-444553540000})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; DT; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Hotbar 4.2.1.1362)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Q312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; QXW03371)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Win 9x 4.90; AN10HaendlerWelcomeletter1200; AO1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Win 9x 4.90; Creative; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Win 9x 4.90; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Win 9x 4.90; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows 98; Win 9x 4.90; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows NT 5.0; BTT V3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 9.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 9.0; Windows 98; Win 9x 4.90; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 9.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; CS 2000 6.0; Wal-Mart Connect 6.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; CS 2000 6.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; CS 2000 6.0; Windows 98; YComp 5.0.2.6)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; CS 2000; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; CS 2000; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; AOL 6.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; AOL 7.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; Windows 95; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; Windows 98; {476BCB60-A826-11D8-9866-444553540000})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; Windows 98; AT&T CSM6.0; YComp 5.0.2.5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; Windows 98; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSNIA; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSNIA; Windows 98; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSNIA; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSNIA; Windows 98; Win 9x 4.90; MSNIA)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 3.11)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; AN10HaendlerWelcomeletter1200; AO1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; A&R Internet; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; BCD2000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; BPB32_v2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; CSO 3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; indo.net IE40 users)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; iOpus-I-M)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; iPrimus)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; IT-Office)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; OptusIE501-018)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; OptusIE55-31)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; OptusIE55-31; BPH03)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; PC Games Hardware)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; QXW0333s)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; QXW0333x)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; QXW0334j)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; qxw03377)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; QXW03395)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; StumbleUpon.com 1.758)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; surfEU DE S3)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; SYMPA)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; T312461; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; T312461; UDWXQ08154711; Praise and Worship to the Lamb of God!)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; TBP_6.1_AC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; TBP_7.0_GS)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; Tucows)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; wave internet services-LAN)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; WSIE)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; )" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98;)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)." + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible;MSIE 5.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible;MSIE 5.5; Windows 98);" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0(compatible; MSIE 5.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; 1 & 1 Internet AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; {25FDDD80-7A10-11D9-B0EA-00055D3406F7})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; 3301; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; {88CC0240-7784-11D9-B0EA-00055D3406F7})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AIRF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AT&T WNS5.0; AT&T WNS5.2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AT&T WNS5.2; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AUTOSIGN W95 WNT VER01)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Avant Browser [avantbrowser.com])" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AWWCD; OptusIE501-018)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; {B0727E40-7BFF-11D8-BF96-00028A14743D})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; {B85C43C0-6408-11D8-890A-005004AD1452})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; BPH32_59)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; brip1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; BTopenworld)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Chariot; Hotbar 4.3.2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; CNE-Internet 02252000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; COM+ 1.0.2204)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Compaq)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Compaq; PeoplePC 2.3.0; ISP)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Config C; Config D)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Config D; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Creative)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; CSO 3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; CWMIE55WDU)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DAC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DIL0001021)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; distributed by ish)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT; Hotbar 3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT; http://www.Abolimba.de)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT; MSIECrawler)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; */E-Plus-002)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; ESB{1B6DEFA6-3A18-4B9B-9022-99348A8910CF})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; {FE627F21-305D-11D9-A75F-00055D2D4DD4})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; freenet 4.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; FunWebProducts-MyWay; DVD Owner)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; GlobtelNet)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; HanseNet ADSL v1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Hotbar 4.3.1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Hotbar 4.3.2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Hotbar 4.5.1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; HTMLAB)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; HTMLAB; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Installed by Symantec Package)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Jet2Web Internet Service GmbH)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; KITV4.7 Wanadoo)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; KSK sp. z o.o.)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; L1 IE5.5 301100)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; MRA 3.0 (build 00614))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; MSN 6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; MSOCD; AtHomeNL191)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; NetCaptor 6.2.1A)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; .NET CLR 1.1.4322);JTB:15:82cffcc4-8761-4b59-9ba1-c2cba02980a7" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; N_o_k_i_a)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; OptusIE55-31)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; OptusIE55-31; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; OptusIE55-32)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; OTCDv1.4)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; PeoplePC 1.0; ISP)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Q312461; T312461; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0300Z)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0333s)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03346)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03347)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03349)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0334h)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0334j)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03354)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03356)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0335n)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0335o)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0335v)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0336b)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03373)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; qxw03376b)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0337i)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0337t)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0338o)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0338t)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0338t; MSIECrawler)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0530g)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; (R1 1.1))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Royal Perth Hospital)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; salzburg-online)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; SiteCoach 1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; sureseeker.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; surfEU DE M2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; surfEU DE S1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; surfEU DE S3)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T312461; Cox High Speed Internet Customer)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T312461; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T312461; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T312461; V-5.5SP2-20011022)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; TBP_6.1_AC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; TBP_7.0_GS)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; TBP_7.0_GS; DefensiveSurfing.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Teleos)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Teleos; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Terminal)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; tn3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; tn4.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Turk Nokta Net; AIRF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; version55)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; VNIE55)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Wanadoo 6.0; Feedreader)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98) WebWasher 3.3" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Wegener Arcade)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; A084)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AIRF; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AN10HaendlerWelcomeletter1200)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AN10HaendlerWelcomeletter1200; AO1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Arcor 2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AtHome021SI; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AVPersonalSerial 728479f8326c352757535b791d2e62b027776bc6)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Circle0701)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; CNE-Internet 02252000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Creative)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; {D7B0F19C-92C9-4506-96FC-7357186B5914})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; DT-AT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; DT; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; DVD Owner)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; EDISINETD02)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; FDM)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Feat Ext 19)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; freenet 4.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; FunWebProducts; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; FunWebProducts; MSIECrawler)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; H010818; BTT V3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; H010818; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; HEP AS; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Hotbar 3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Hotbar 4.1.8.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Hotbar 4.3.2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Hotbar 4.4.2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; IDL Internet)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; iebar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; iOpus-I-M)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Kit Terra Premium; FunWebProducts),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; libero)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MSIECrawler)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MSN 6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MSN 6.1; MSNbBBYZ; MSNmen-us; MSNc21; v5m)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MSOCD)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MyIE2; FunWebProducts; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705; Hotbar 4.6.1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705; Hotbar 4.6.1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; ntlworld v2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; ONDOWN3.2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; OptusIE55-31)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; pbc4.0.0.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; PeoplePal 3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Q312461; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; QXW0335v)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; sbcydsl 3.12; YComp 5.0.8.6; AT&T CSM6.0; AT&T CSM7.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; ScreenSurfer.de)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; SNET OLR v5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; SPINWAY.COM)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; StarBand Version 4.0.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; StumbleUpon.com 1.760; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Supplied by blueyonder)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; surfEU DE M2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; T312461; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; TBP_7.0_GS)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; tele.ring Version 4.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; TUCOWS)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; V1.0Tomorrow1000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; V1.0Tomorrow1000; Q312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Wanadoo 5.4; Wanadoo 5.5; Wanadoo 6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; www.vancouver-bc-canada-guide.com; NetCaptor 7.2.2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; YComp 5.0.2.5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; YComp 5.0.2.6)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; ZDNetIndia)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; ZDNetIndia.com browser)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; ZDNetIndia; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; ZDNetSL)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Zon CD-rom versie 2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows CE)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; 1 & 1 Internet AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; 1&1 Internet AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; AIRF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; by IndiaTimes)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; c_commcd1; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; CHIP Explorer :-)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DekaBank; DGZ-DekaBank; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DERA IE 4.01 Install 1.0.0.6-CD)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DEV4012; SP4012)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DigExt)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DigExt; QXW03346)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; ENR 2.0 emb)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; F-5.0.0-19990720)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; FR 09/05/2000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; FunWebProducts; Hotbar 4.4.5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; GDMS_98A_BRAZIL)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Gothaer Versicherung Mobil)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; H010818; DoJ-SOE-4.0.0.0-build-20000213)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; H010818; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; H010818; HEWLETT-PACKARD -- IE 5.5 SP1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Housenet Full 1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Humana1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; HVB 2/2001; T312461; HVB)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; ICN - 000407; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; IE55232Ab)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; i-NavFourF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Installed by Symantec Package)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; IT-Office)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; L1 IE5.5 December 2000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Logica 5.01.1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; LycosDE1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; MATAV_IE_55_HUN)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; MI Brandenburg; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; MSIE-5.5-DZBANK)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; .NET CLR 1.0.3705; Googlebot; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Googlebot)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; N_O_K_I_A)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; norisbank; iOpus-I-M)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; P20314IEAK1; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Provided by UAL)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW03002)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW0330d)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW0333v)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW03346)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW0334h; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW03356)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW03371)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; RBPD2711)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Sema UK Telecoms upgrade)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; SQSW)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Suncorp Metway Ltd)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; IK)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; (R1 1.1))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; Unilever Research)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; TIN ie4a32bit rel.1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Tucows)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; USHO-111203)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; v4.0 C3; v5 C5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Version 2/5.5 Customised)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5;Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; 1 & 1 Internet AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {2F8067D2-867C-4351-A289-786E8307965E})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; 3304)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; 3305)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; 360networks)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {4D391717-5781-46B1-9B5E-82D8014C43B0}; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {54ACD89C-CE9B-4CD3-9617-E30DE3DA8738})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {5A4938A5-F50D-46DE-80AA-C659EC68625D}; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {5C8D4EB8-815B-42DD-BF83-63A5F7F7377D}; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {63AE5C75-6D69-4DC2-B8E2-F8E204D31206})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; 828750)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {A4E04F4A-3C7A-484D-B1E0-DE64E78EB309})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) Active Cache Request" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {AF9A0710-ED4B-4DEE-884C-E0BB887C2E44})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Agilent Technologies IE5.5 SP2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Agilent Technologies IE5.5 SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Airservices Australia)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; AspTear 1.5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; AT&T CSM7.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; AWWCD)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; bkbrel07)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; BOCSIE55SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; BTopenworld)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) But of course, that's a fake. I'm really running Mozilla on a non-Microsoft OS, and I've only set these headers to get around the restrictions of people who are ignorant enough to exclude the browser that " + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {C89A4139-160D-4323-B132-B58019B2AF1A})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CBC/SRC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CHEP Australia; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CHMC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Coles Myer Ltd.)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; compaq)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; compaq; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Config D)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Config D; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Connex 13/02/2001; Connect 25/07/2002)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Creative)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CSC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CWMIE55WODU)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CWMIE55WODU; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DAF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Dept. of Primary Industries)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DEUBA)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DGD (AutoProxy4))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DPU; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DT; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; [eburo v1.3])" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; [eburo v1.3]; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; [eburo v1.3]; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {EE17FE27-30FE-41A1-992C-71356B0262D1})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; ESB{FC3DA1FF-49D4-4235-B656-6358FBC0D57B}; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; FDM)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Fisher-Price)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; FREE; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; FunWebProducts; maxweb)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; GameBar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; GEP IE 5.5 SP2 Standard; GEP IE 5.5 SP1 Standard)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Groupe DANONE)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; 828750)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; Navstd27juin2001en)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; Q316059)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; UB1800; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Hotbar 2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Hotbar 4.1.8.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Hotbar 4.2.8.0; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Hotbar 4.4.5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; HTMLAB)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; ICT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Installed by Symantec Package)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Installed by Symantec Package; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; iOpus-I-M)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0);JTB:104:a95eef30-9f35-4ec0-bc43-66a16a703faf" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; KSK sp. z o.o.)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; LCPL)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; LILLY-US-EN)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; LLY-EMA-EN)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Logica 5.5 SP2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Merrill IE 5.5 SP2 Install Kit; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; mhs)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; MSOCD; AtHomeEN191)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Nambour State High School (Queensland Australia); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2914)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; N_o_k_i_a)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; N_O_K_I_A)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Nokia 7650; 240*320)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; N_O_K_I_A; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; NSW.net)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; nwb)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; OptusIE55-31)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; OptusIE55-31; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Oregano2 )" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Patriot V5.5.1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; PRU_IE55SP1; PRU_IE55)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Q312461; iOpus-I-M)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Q312461; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; QXW0336o)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; qxw0337d)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; QXW0338d)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; (R1 1.1))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; RA; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; RA; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; RC7.4 release)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; RC7.4 release; i-NavFourF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; SCF - Mean & Nasty; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; SDS IE5.5 SP2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; S.N.O.W.2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; S.N.O.W.2; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; surfEU DE M1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; SWS)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; CAT-COE)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; DOJ3jx7bf)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; F-5.5SP2-20011022)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; F-5.5SP2-20011022; F-5.0.1-20000221)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; Guidant IE5 09302001 Win2000 Distribution; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; istb 702; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; ITS 2.0.2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; MSIECrawler)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; PC SRP 2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; POIE4SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; TBPH_601; Feat Ext 19)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; TheFreeDictionary.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Thiess Pty Ltd)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; U)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Unknown)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; www.ASPSimply.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; www.bfsel.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; WYETH)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; YComp 5.0.8.6)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; ZDNetIE55)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.7 [en] (compatible; MSIE 5.5; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.8 [en] (compatible; MSIE 5.5; Windows NT 5.1; U)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible;MSIE 5.5; Windows 3.11)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible;MSIE 5.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows XP);" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.1 (compatible;MSIE 5.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/7.2 (compatible; MSIE 5.5; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "MSIE 5.5" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5.1; Windows NT 4.0; T312461; spw500; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "MSIE 6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 (compatible; MSIE 6.0; Windows 98; 240X320; PPC; Default)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.00; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 5.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 5.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 5.0; Windows 98; Win 9x 4.90; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows 98; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows 98; Win 9x 4.90; Q321120)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows 98; Win 9x 4.90; freenet 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; FunWebProducts; SV1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Hotbar 4.3.2.0; BCD2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Hotbar 4.4.7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; PCUser; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Q321120; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Q321120; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; {5F4036E0-6271-11D8-8929-000AE67C2897})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; AT&T CSM6.0; FunWebProducts; Hotbar 4.2.9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Compaq)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; GA55sp2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98);JTB:2:825c2721-bc07-11d8-bdea-444553540000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Win 9x 4.90; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Win 9x 4.90; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Win 9x 4.90; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Win 9x 4.90; OUBrowser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; {1EB73F69-5BFB-4D8C-9BA8-72A428DA75D3}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; {3B4748F2-EE14-4317-B069-7AB6F7AEFE69})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; BTOW V9.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; CDSource=storecd_01_03; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; CDSource=v9e.05)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; generic_01_01; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; Hotbar 4.4.6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SaveWealth)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; StumbleUpon.com 1.751)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1; FunWebProducts; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; YComp 5.0.0.0; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; YComp 5.0.0.0; SYMPA; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Win 9x 4.90; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Win 9x 4.90; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; YComp 5.0.0.0; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {07D8E8DA-0530-4B69-A0A4-7EB7CB54C821}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {2E4B39C0-67F6-4E50-BD40-FAD19B5CAA8A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; 3305)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {7197B170-E810-4522-9DC0-088AAD5AD6E9}; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {723EBBEB-CBB8-4A00-AD75-0A0B1A0517ED})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {8B658E16-E35C-4C43-A913-307AA2BADC55}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {9CCDF57C-A828-47C1-9431-3670BDEC44B6}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {9D60457B-6A0F-4CAF-8C22-B463BC201CBB})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; BCD2000; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; CDSource=storecd_01_03; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; CDv5.1.1_1099)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {D2F65954-6A14-43B5-86BE-42556275B763})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; dial)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; ESB{67E15522-64F5-4326-B157-10FF147CA5E9}; ESB{EF27D6C9-1D19-4ED9-B494-FA921D24CCB0}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {FD960C72-0B96-40FA-BFF5-6B1CE3F64B60}; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; SV1; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; YPC 3.0.2; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; generic_01_01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Hotbar 4.2.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; iOpus-I-M; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Preload_01_07)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Q312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Q312461; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Roadrunner; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; Creative; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; FunWebProducts; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; Grip Toolbar 2.07a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; Media Center PC 3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; v8c.01; Hotbar 4.2.11.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Wanadoo 5.5; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.9; Beta 0.9.4201.270; Browser Control 0.9.0.4; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; {DB0219C0-5374-11D9-81F0-00010292A080})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; GTelnet1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98) OmniWeb/v496" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; Win 9x 4.90; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 4.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 4.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; iOpus-I-M; SEARCHALOT.COM IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows 98; Compaq)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows NT 5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows NT 5.1; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; AOL 8.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; AOL 8.0; Windows 98; {99AEF9F6-AD65-4E28-B512-F173232EBD29})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; AOL 9.0; Windows 98; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla /4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; AT&T WNS5.0; AT&T CSM6.0; AT&T CSM8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; FunWebProducts; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; iPrimus; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; PCUser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; sureseeker.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; sureseeker.com; searchengine2000.com; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows NT 5.1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.6; Windows 98; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.6; Windows 98; T312461; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.6; Windows 98; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; Hotbar 4.3.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; MSOCD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; T312461; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; Win 9x 4.90; AT&T CSM6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 3.1; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 95)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 95; PalmSource; Blazer 3.0) 16;160x160" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/ 4.0 (compatible; MSIE 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98);" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible;MSIE 6.0;Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 100)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 1&1 Internet AG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 1&1 Puretec)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 1&1 Puretec; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {12Move})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 1.57.1 )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {1A030500-6279-11D8-91F9-00055D306537}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {29C5C4C0-87CA-11D8-94C0-00E07DE10B20})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {3171E4C0-49BB-11D9-8CA9-D07E76ABD032})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 3304; MSN 8.0; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 3305)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {57F5F0C1-E226-11D8-A9B2-00C04F5BBF26})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {62FF51C0-7B8B-11D8-AD78-004F4905E079})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {6C917480-655F-11D8-8622-444553540000})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {728C4D40-8C75-11D9-86F6-D73001167134}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {7E8AF401-1A03-11D9-BF45-444553540000})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {7EC49A61-187E-11D9-824D-0008A15DF7A2}; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {8F9DB3A0-A757-11D8-A1FE-444553540000}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {9C20C200-1109-11D8-8F74-444553540000})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AIRF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AIT; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; alice01; DP1000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; alice01; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; alice01; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Alitalia Custom)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; APC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; APCMAG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AskBar 3.00; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AskBar 3.00; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AtHome0107)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AtHome0107; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AtHome033)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AtHomeI0107)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AtHomeI0107; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T CSM6.0; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T CSM6.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T CSM6.0; Q312461; AT&T CSM7.0; AT&T CSM8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T WNS5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T WNS5.0; MSOCD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; austarnet_2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AUTOSIGN W2000 WNT VER03)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Avant Browser [avantbrowser.com]; OptusNetDSL6)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {B3EB8D41-DE48-11D8-BBF4-00804815CB32})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BB1.0 IE5.5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {BBA839A0-7F6C-11D9-8278-0080C8E10726})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BCD2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BCD2000; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {BDBAC461-139C-11D9-B962-00A0CCD11F28})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BIGPOND_ADSL_42)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BIGPOND_ADSL_42; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BPB32_v2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; bpc; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BPH03)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BPH32_55a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BPH32_59; OptusIE501-018)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BTO E1.07; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BTOW)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BTOW V9.0; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BTOW V9.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BTOW V9.5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {CA066580-6E9C-11D8-97BC-0060088DA696}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; CDSource=cannonst)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; CDSource=v2.15e.04)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; CDSource=vBB1c.00; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Centrum.cz Turbo2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Compaq)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Computer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Cox High Speed Internet Customer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Cox High Speed Internet Customer; NetCaptor 7.5.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Cox High Speed Internet Customer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; cPanelGui 6.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Creative; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; CSOLVE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DCSI)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Deepnet Explorer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DigExt; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DIL0001021; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DP1000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DVD Owner; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {E39750C0-6F5B-40B4-9D70-0681DB8795DA})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; eBook)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)::ELNSB50::0000411003200258031c016c000000000506000800000000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)::ELNSB50::0000411003200258032001df000000000507000900000000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)::ELNSB50::000041100400030003de0208000000000502000800000000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)::ELNSB50::000081900320025803140197000000000502000800000000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; ESB{13B30CE0-EC80-11D8-83BE-0001031746AB})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; ESB{BBA298E0-3889-11D8-9F02-0010B5525635})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; ESB{F0B8BB20-643F-11D0-9C90-00C0F0741766}; yie6_SBC; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; ezn73ie5-1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; EZN/PC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; EZN/PC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {F361FD20-F590-11D7-AFAF-0050FC225B60})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; F-5.0.0-19990720; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {FD464440-B8BD-11D8-9957-00010273BF2C}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; formatpb)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FREE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; freenet DSL 1.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; freeonline)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; fs_ie5_04_2000i)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; fs_pb_ie5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; FunWebProducts-MyTotalSearch)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts-MyWay; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; NN5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; GFR)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; Hotbar 4.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; i-MailBook)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; MathPlayer 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; VZ_IE6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hellas On Line; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.1.8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.3.1.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.3.2.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.3.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.4.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.5.1.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.5.1.0; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; HTMLAB; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; ICONZ IE5CD; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; IDG.pl)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; IE5.x/Winxx/EZN/xx)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; IESYM6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iiNet CD1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; i-Nav 3.0.1.0F)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Installed by Symantec Package)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; InterNetia 0002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iOpus-I-M; ISP40; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iOpus-I-M; MyIE2; FunWebProducts-MyWay)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iOpus-I-M; NetCaptor 7.5.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iP-BLD03)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iPrimus)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iPrimus; OptusIE501-018)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98);JTB:140:1255fb21-285b-11d9-bc23-444553540000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98);JTB:15:344477a2-2c6d-11d9-a611-000854034fa2" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; JUNO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; JyxoToolbar1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; KB0:176933)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; KPN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MADE BY WEBO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MathPlayer 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MathPlayer 2.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MathPlayer 2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MindSpring Internet Services)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSN 8.0; MSN 8.5; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSN 8.0; MSN 8.5; MSNbQ001; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSN 9.0;MSN 9.1; MSNbQ001; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSN 9.0; MSNbBBYZ; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSOCD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSOCD; AtHome021SI; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSOCD; AtHomeEN191)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSOCD; Cox High Speed Internet Customer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSOCD; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MyIE2; iOpus-I-M; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MyIE2; Q312461; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Neostrada Plus 5.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Neostrada TP 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Neostrada TP 6.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; NetCaptor 7.5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; NetCaptor 7.5.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; NN4.2.0.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE501-018; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE501-018; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE55-27)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE55-28)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE55-31; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusNetDUI6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OZHARLIT6.0_1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OZHARLIT6.0_1_PP3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OZHARLIT6.0_1_PP3; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Panoramic IT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCM_04; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCM_06a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCQuest)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCQuest; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCUser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCUser; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCUser; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PeoplePC 1.0; hpford)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PeoplePC 2.4.5; ISP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PeoplePC 2.4.5; ISP; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Pioneer Internet - www.pldi.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PKBL008; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PowerUp IE5 1.01.02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; pro)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; provided by blueyonder)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; AT&T CSM6.0; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; DF23Fav/2.5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; H010818; yie6_SBCDSL; sbcydsl 3.12; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; YComp 5.0.0.0; NN5.0.3.3; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q321017)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q321120; Feat Ext 1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW03398)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW03399)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0339a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0339b; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0339c)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0339d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0339m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW03404)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0340e; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0340k)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW03416)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.1); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.3); (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Roadrunner; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Rogers Hi-Speed Internet; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; sbcydsl 3.12)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SEARCHALOT.COM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Sgrunt|V108|867|S538318592|dial; snprtz|S03066638220053; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SIK1.02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SIK30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SIS; {SIS})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SiteKiosk 5.5 Build 36; HBBKLP01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Skyline Displays, Inc.; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SL102000; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SpamBlockerUtility 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Spartipps.Com PS Edition; iOpus-I-M; MyIE2; DX-Browser (V4.0.0.0; http://www.dxbrowser.de))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SPINWAY.COM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Strato DSL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; StumbleUpon.com 1.735)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; StumbleUpon.com 1.758)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; StumbleUpon.com 1.760; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Superonline)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Supplied by Cloudnet, Inc.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; supplied by tiscali)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; sureseeker.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SYMPA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SYMPA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Hotbar 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Newman College)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Q312461; Hotbar 4.0; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; V-5.5SP2-20011022)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TBP_6.1_AC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; tco2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; telus.net_v5.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; telus.net_v5.0.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TencentTraveler )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TeomaBar 2.01; Wysigot 5.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; tiscali)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TNET5.0NL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T-Online Internatinal AG; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Total Internet; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TUCOWS; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TUCOWS; Q312461; FunWebProducts; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Ubbi)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; V1.0Tomorrow1000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; v11b.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; V-5.5SP2-20011022)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; VNIE5; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; VNIE5 RefIE5; SCREAMING_IE5_V2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; VNIE60)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; VZ_IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; VZ_IE6; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; W3C standards are important. Stop fucking obsessing over user-agent already.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Wanadoo 5.6),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Wanadoo 6.0),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Wanadoo cable; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; WC/qrDwCOdiRzNfl)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Web Link Validator 3.5" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) WebWasher 2.2.1" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; WestNet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; 1&1 Internet AG by USt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; {2A23FA2A-F9FD-484E-801D-DF232F7C64BA}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; {74787047-5497-4FC4-8302-D08B74E01B4B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AT&T CSM6.0; AT&T CSM8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AT&T CSM6.0; VZ_IE6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AT&T ELC5.5; T312461; {Cablevision Optimum Online})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AT&T WNS5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Avant Browser [avantbrowser.com])" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Avant Browser [avantbrowser.com]; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Avant Browser [avantbrowser.com]; YPC 3.1.0; iOpus-I-M; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; BIGPOND_ADSL_42)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; BIGPOND_ADSL_42; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; brip1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; BT Business Broadband)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; BT Openworld BB; YPC 3.0.2; FunWebProducts; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; BTopenworld; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; {C954D864-F84E-7490-1E6D-7AF74AE2E175})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; CDSource=ALLIED_01_01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Charter B1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Cox High Speed Internet Customer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; c't)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; DT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; DT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; DT; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; DT; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; {E895B1EF-805F-4965-88D8-54AF2D5541F7})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; EnterNet; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; ESB{6BC1B80D-8E38-4080-99B0-2440E59328A1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; {F77382BC-AB24-49B4-8059-71D9365FEEB2})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FREE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; freenet 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FREESERVE_IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts-MyTotalSearch; FunWebProducts; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; generic_01_01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; H010818; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; H010818; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.2.11.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.2.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; HWE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; iebar; MSN 9.0;MSN 9.1; MSNbQ002; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; JJ)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Mailinfo [1999999999999999])" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSN 9.0;MSN 9.1; MSNbQ002; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSN 9.0;MSN 9.1; MSNbQ002; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSN 9.0; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSOCD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSOCD; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MyIE2; Free Download Manager)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; ONDOWN3.2; AtHome021SI)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OptusIE55-31; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OptusIE55-31; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OptusNetDUI6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OUBrowser; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; PC ACTUAL (VNU Business Publications España)),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; PCUser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; PCUser; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; PCUser; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Provided by Alphalink (Australia) Pty Ltd; H010818; FunWebProducts);JTB:15:d16f74f8-64d6-4024-a74d-b8724a1c548c" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; FtSoJ 666)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; LDE0308a; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; YPC 3.0.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q321120; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Queens-ITS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; QXW0337s)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Rough Cutz)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; sbcydsl 3.12; FunWebProducts; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; sbcydsl 3.12; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; SIK1.02; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; SIK30; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; son0302CD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Sunet v2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Supplied by blueyonder)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Supplied by blueyonder; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Supplied by blueyonder; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; SYMPA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T312461; Headline-Reader; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T312461; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T312461; Wanadoo 5.3; Wanadoo 5.5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T312461; Wanadoo 5.5; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; TeomaBar 2.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T-Online Internatinal AG; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Virgin 3.00; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; VZ_IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; VZ_IE6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Xtra)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YComp 5.0.2.5; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; yie5.5_SBCDSL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; yie6_SBC; YPC 3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YPC 3.0.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; WRV)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; www.ASPSimply.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; www.k2pdf.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; www.spambully.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Xtra)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Xtra; Hotbar 4.3.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0; Cox High Speed Internet Customer; sbcydsl 3.12" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.2.4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.2.5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.2.6; IESYM6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDial; YPC 3.0.0; FunWebProducts; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; sbcydsl 3.11; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; sbcydsl 3.12)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; sbcydsl 3.12; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; sbcydsl 3.12; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBC; YPC 3.0.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.0; BT Openworld BB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.2; BT Openworld BB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.2; BT Openworld BB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.1.0; yplus 4.5.03b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; MyIE2; PPC; 240x320; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows compatible LesnikBot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; 11-12-2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; 3COM U.S. Robotics)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; ABN AMRO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; AIRF; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; APC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Aztec)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Bank of New Zealand)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; BVG InfoNet V5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; CLS4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; CNETHomeBuild03171999; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; COLLAB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; Config C V1.3; v5 C5; Config D V1.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; Config D V1.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; v4.0 C3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; v5 C5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config D V1.3; Config A V1.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; CT2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Deepnet Explorer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; digit_may2002; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; eircom/june2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Girafabot; girafabot at girafa dot com; http://www.girafa.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; H010818; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Hays Personnel Services)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Hotbar 4.1.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Hotbar 4.4.5.0; Config A V1.0; Config A V1.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; HVB 2/2001; HVB-GROUP, 0001_CIT; spunt-ois-intranet; ois-intranet; HVB: NT-OIS; HVB; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; HVB 2/2001; HVB; NT-Zentrale; HVB-GROUP, 0001_Zentrale; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; IE55CX1; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; JPMC_CDI)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; MCS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; MRA 2.55 (build 00423); MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; MSIE5.0; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; NAB PC IE6SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; NetServ; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; P20314IEAK1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; PCQuest; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; PCUser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; po; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Q312461; QXW0339m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Qwest - 11122003-a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; QXW0339c)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; QXW0339m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; RBC; 9LA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; RZNT2000.010)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; SDE 2/12/02 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; STIE5-000710)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; supplied by tiscali)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; DI60SP1001; DOJ3jx7bf; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; Hotbar 4.1.8.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; Q312461; (R1 1.1); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; Q312461; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; SI; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; terranet.pl; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; TESIEAK6a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; TTC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Union Pacific Corporate Image)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; v1.0 C1; v4.0 C3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; v1.0 C1; v4.0 C3; iOpus-I-M; v2.0 C1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; v1.0 C1; v4.0 C3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; www.ASPSimply.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Yahoo-1.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; YComp 5.0.0.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible;MSIE 6.0; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {01B9B056-41CF-4C49-9F15-FBFD356FACB9}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {06123460-5191-47D8-9801-E64CEE8E7D7C}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {061F9742-FB3A-4B13-8D81-F1DBCFA49E24})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {06537897-63B2-495D-BD75-97D5F17AEF61}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {0D43CA9A-9A2A-4AD3-9FB3-D11ED856701C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ¾ÜÆÄÀÏ (atfile.com); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {109E9252-FC9D-4712-9D79-AC1C6061FD02}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 1&1 Internet AG by USt; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 123-Reg The Cheapest & Easiest Way to Get a Domain Name)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {12AB035D-BD79-4DED-B042-E95ED524B435}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {143F7CDC-2BEF-45ED-9CA0-9B2076F467D4}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {144098F2-DE3D-4A0E-AA56-C97DABCBEC15})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 1.57.1 )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {19449247-55EC-4B9A-A99C-A1FD75AB322A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {1AAA4471-A825-4D94-9F91-18DF18D97101}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {1B07E273-0A6C-440D-8E04-CBB9F30106AD})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 2.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {282E02E6-44BF-4FF6-9C84-59755CC87202}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {298A087F-0FE1-40C9-A893-97A76A73F88E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {2C0881E9-B6B7-45DB-BFDF-F70BB47FA680}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {2DABB6D9-031A-4174-9C59-D87776C152AC}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {2E487848-058A-4532-83EE-AFF12A987739}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {305B1A70-D1DC-45EF-AA35-F707BBEE85EC}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 3303; iebar; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {338C77F9-6668-40F2-B9AA-7B8B3AACAADA}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {3504DB01-C872-40F5-90A1-A76E8C7BA7F8})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {359046E3-C000-44A8-90B3-BA1FA146D3ED}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {3FD9CEF8-894A-4FFE-BD59-6B3A28A6967A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 3M/MSIE 6.0;; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 3M/MSIE 6.0;; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {4E075391-5B06-46A7-872B-70EB64C44294})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {4EC4D46A-2224-42E4-B20E-263A00146AD5}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {4F1675AF-7549-42E8-A055-6E4554DDB2B6})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {53D150F0-3948-40FB-AED0-BC12A07D16CB}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {57B317DC-AF18-477D-B26C-D635B7BC0C6C}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {59290DD6-57E1-419C-A050-BC983EB72656})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {5C6515F0-765B-4AD8-A168-3761FB537EBB}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {5DB0254E-3F8C-4DDA-A3D4-6C543537187B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {607C5361-86F7-42A1-8BC4-E3BB7EF36E49}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {62BA8785-A517-4CF6-8456-56716A6D1158}; iebar; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {649E2463-3332-4F08-A0B1-8CCC13C2A5B6}; CLX-IE-5.5sp2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {665CA5DF-6149-4382-9952-7B39C4A56AD1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {68B11FD1-3CDB-4433-8D4B-FAC8D8352E6E}; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6B81900A-D6AA-461E-8FC6-1620330AC921}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6B9216F6-4521-47B0-B084-2A8E511A0B9F}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6D3765E4-9B4F-43FA-A724-82E2F0EF0D1F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6E0F184F-9748-4A0E-8B0C-F812273A1D33})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6E678899-843C-496E-9B27-A35206C3E26B}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6EFA4147-88FB-4570-8DA4-EE21FA159006}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {70E73558-8F52-4A75-9312-C8E68DEDAB57})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {7144A0D4-D427-4095-B265-D15A8756742F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {79AF7E55-D81C-44D9-8636-94129DF9DF37}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {79CEA9FC-BE53-45A3-B81D-B66479A78C7D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {7A9D705C-6447-43AF-9CBD-F3EBBC64467D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {8036F106-4980-4D9C-8E40-BC990D1C5340}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {81629412-DDAE-4320-9573-1909044055F5})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {86464A58-0461-4217-8D58-67F6F1813A02}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {89CD3E7F-86F4-4766-8A15-773ED2B1ECDA}; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {90333DAB-0FE6-4FE7-9F0A-37211DA1DD26})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {90A67E22-1FA8-46DB-913D-5BFAB83B9187}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {9444DFA5-F00A-4C9C-A481-D228454293AC})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {96C6F6D2-27AB-4CE8-A693-5FB34DED41C9})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {9C8127EF-235E-4DB5-A132-FB67DCB6DB9E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 9L5.5; 9LA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A253E2A3-43A6-4F7C-ACE5-7ACE750E8496}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A26143E3-E395-4A08-906C-2094F96F9992}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A39C4CA3-D28E-48DF-A362-5D0862045D4B}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A45DB481-08E3-4625-85C0-18D272EFA672})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A5E3D903-A7D5-493D-8319-D7A126A43C4E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A64C95F3-2891-4793-8163-A6165CF588EC})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A6B5140D-D366-4853-A784-224D481F964A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A6E2595A-77BF-4A90-BDD6-581660B19BAF}; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AAL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ABACUS LABS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Abbey National PLC; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Abiliti Solutions; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ABN AMRO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ABN AMRO; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ABN AMRO; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Agilent Technologies IE5.5 SP2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Agilent Technologies IE5.5 SP2; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Agilent Technologies IE5.5 SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AGIS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AIRF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AIRF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AIRF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AJA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Alcatel Portugal IE6 SP1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Alexa Toolbar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; alice01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ANZ Banking Group)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ANZ Banking Group; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AOL 9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APC; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APCMAG; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APCMAG; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APCMAG; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APCMAG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APC; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AQL - Groupe Silicomp; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AskBar 3.00; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AskBar 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AskBar 3.00; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; AT&T CSM 6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; www.ASPSimply.com; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM7.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T WNS5.1; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser 6.5.1.3 [avantbrowser.com]; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser 7.0.0.8 [avantbrowser.com]; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; Feedreader)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; i-NavFourF; NetCaptor 7.2.2)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avi 1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {B0B866F5-5095-4A87-AD12-D436006DEE38}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; b2c01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {B42D1284-FDB2-4F37-A1DF-857CBBCA89B2})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {B75CE5DB-567A-44D7-920D-1228B51B3B3E}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Bank of New Zealand)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BAssF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BB1.0 IE5.5.2; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BB1.0 IE5.5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BB&T Standard Load (IE 6 sp1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BCD2000; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BCIE6SP1; .NET CLR 1.0.3705; Working 081103 Rev 6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BCUC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; bfz Aschaffenburg)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; bgflie; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BIGPOND_ADSL_42)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BIGPOND_ADSL_42; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Boeing kit)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Boeing Kit)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Boeing kit; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Boeing Kit; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Boeing kit; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BOTW)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BOUK)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; brip1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; brip1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BSS; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BT [build 60A])" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; btclick.com Build BTCFMFQ3; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BT Openworld BB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BTopenworld; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; bull ;-) ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Business 1st; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BWL 5.5 IEAK; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; by Hi-HO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; c20010830)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {C545DFFA-2A55-4A99-AC19-EB846E5457EA})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {C5C1AC35-93B1-48C0-BAD1-FD616C71A118}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {C6A15346-4AC9-4272-8CF7-151480C6A9D4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {C7132536-FBAC-4135-9D87-C6DEC6B0AFE0}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {C8EA929F-150F-4C5F-81E2-A258BEDBF712})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {Cablevision Systems Corporation})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {CB1C5177-05C4-4DFE-B687-AD6AF39ACD3E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {CB46BCEF-212D-452A-9341-734FBBA61540}; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CBC/SRC; Hotbar 4.4.9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CCSU; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {CD8D3547-6274-46D5-947D-12B00C362FD5}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=ALLIED_01_01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=ALLIED_01_01; ESB{1A596234-D5AD-49CF-A3D5-B814562D9F84})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=ALLIED_01_01; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=BP1b.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=BP1b.00; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=v2.15e.03; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=v2.15e.04)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=vBB1c.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {CF867BA5-3DE3-4197-A46B-0C7BBF5C2285}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {CF8E2F64-C6B1-4DAE-BFDE-0D69737FAA8A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Chemopetrol)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CHOP_IE55_V2; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CHWIE_SE60)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CIBA SC Standard Setup)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CIBA SC Standard Setup; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; City of Mesa, Mesa, AZ, USA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CL_P2K_1_1_2_1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CNGTRUST)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CO770; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Coles Myer Ltd.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Coles Myer Ltd.; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Coles Myer Ltd.; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; COM+ 1.0.2204)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Combellga; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; compaq)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Compaq; DigExt; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; compaq; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; compaq; T312461; Hotbar 4.1.8.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Compatible; Version; Platform; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Computer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Computer) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Config D; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Conman 2.5; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Cox High Speed Internet Customer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Cox High Speed Internet Customer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Cox High Speed Internet Customer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CoxIE55)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CoxIE55; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CPT-IE401SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CPWR)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Creative; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CSMMWebClient1001; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CSUF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; cust 2.01 r7; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Customized by Adrian Connor; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CyberZilla; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {D208973F-8755-4E82-A102-0AAA11511D7B}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {D4183739-BB5C-46AB-B754-64727133F2A5}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {D48C8B2F-108A-48C8-9F5F-058A0125BFB9})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {D86494B1-7D5D-4748-838D-529552349E2B}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {DA7D9C31-C746-405E-A35A-6798A9DD3842})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Data center)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Datavend Internet Services)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DCC=6.SP1-E)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {DD52EB3A-6F72-4BDC-8490-161016E9E39C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Debian Linux; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deepnet Explorer 1.3.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deepnet Explorer 1.3.2; Lunascape 1.4.1)" + family: "Lunascape" + major: '1' + minor: '4' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deepnet Explorer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deepnet Explorer; .NET CLR 1.1.4322; .NET CLR 2.0.40607; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deptartment of Premier & Cabinet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Dept. of Primary Industries)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DeptoMtz/237)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DET_ITD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DHSI60SP1001)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DHSI60SP1001; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DHSI60SP1001; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; dial)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Dialer/1.10/ADSL; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; dial; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Hotbar 4.2.11.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; MyIE2; FDM)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; OZHARLIT6.0_1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Q312461; NetCaptor 7.0 Beta 3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Q312461; NetCaptor 7.0 Beta 5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; ScreenSurfer.de; http://www.ScreenSurfer.de; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Tucows)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; YPC 3.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; digit_may2002; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; digit_may2002; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; digit_may2002; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DIL0001021)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DOF-IE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DOJ3jx7bf; T312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; drebaIE-ZE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DrKW=IEAK; DrKW; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DrKW; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DT-AT; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DT; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {E39E04A9-A873-4BEB-8AC9-8AAE2C5F4B36}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {E4CBDA2C-2AD6-4963-934B-78AA66873B09})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; E5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {E6BC9F59-0BE1-42F0-B30B-28E630FC426C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; [eburo v1.3])" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {EDEBBC92-1A23-4CCF-A287-E7C446EE184E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; EDS; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; eircom/june2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; EMC IS 55; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Endeavour Sports High School)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Era)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ERACON AG; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{18990B24-B930-4963-9F4A-61EC73B586A7})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{262D05ED-F4C4-41AA-9DF8-72398CBAFD6B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{3B40AD5C-7E2F-46D4-9A6A-7C43322AC378}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{3E1AFDF1-14A8-422C-AE93-58363EDEAF96})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{5CEA4270-4309-43DE-913E-4A34AC4DDAC0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{5D6E1D2C-9FB8-4423-8E9D-9AD635CED031}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{6000F0D1-9B3D-429E-9991-2DA84AB29E7A}; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{69A214B6-5A7B-43E5-89D8-E8F4A9946F3E}; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{97B6FDFD-F75F-4CB4-8F1D-FA16B707E202})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{9FFE22ED-496B-4730-B4EA-CFCDCAF1FCAE})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{A6A5FEED-9585-4F90-8424-38ED6FD61D32}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{CDD58A96-417A-4783-B196-B39BD35B879E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{E8E61902-FB81-4DDA-8BD2-1CE907F88866}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{F512E5D9-AF79-49FE-A3A6-83693239F5C0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{F7D303AF-E887-4662-945C-FF4B3413A379}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; EV20020426A; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; EXPRESS_004; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ezn)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {F1EA689F-1B1F-474B-8E21-C2122AD49CE8})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {F30610B3-0195-4745-BFEF-D07509032CA2})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; F-5.0.1SP1-20000718; F-5.0.1-20000221; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {F60857FB-3034-40CF-9E34-A28D3EF30C9F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; F-6.0SP1-20030218)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; F-6.0SP1-20030218; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {FABA9F34-879A-44F2-84B8-83E37CC31579})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FastWeb)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FastWeb; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FCP Intranet Browser; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {FD5A89C5-E2DA-4278-BBCB-B19DA07185AB}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {FD604FB4-DBBF-481F-A46F-543390363E21})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {FDD074C3-CFD3-4CD5-B6FA-1A4AE8C0852D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FDM; COM+ 1.0.2204)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feedreader; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feedreader; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Flow Systems)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; formsPlayer 1.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; formsPlayer 1.3; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FORSCOM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Franciscans Australia; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FREE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FREETELECOM; Wanadoo 6.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FREE; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Fujitsu Services GmbH, Germany; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; bkbrel07)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; FunWebProducts-MyTotalSearch; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; GameBar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyTotalSearch)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyTotalSearch; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; MSIE 6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; .NET CLR 1.0.3705; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.0.3705; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322; Google-TR-1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; (R1 1.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Telia; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FUSAIE55SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GENA SDV2.1; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GEP IE 5.5 SP1 Standard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GEP IE 5.5 SP2 Standard; GEP IE 5.5 SP1 Standard; GESM IE 5.5 SP2 Standard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GEP IE 5.5 SP2 Standard; GEP IE 5.5 SP1 Standard; T312461; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GEP IE 5.5 SP2 Standard; GEP IE 5.5 SP1 Standard; T312461; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GIS IE6.0 Build 20020920)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GIS IE6.0 Build 20031007)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GIS IE6.0 Build 20031007; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GIS IE6.0 Build 20031007; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GMX AG by USt; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Googlebot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GPM - MSIE 6.0 SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Gulfstream Aerospace)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 3M/MSIE 6.0;; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 824145)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 824145; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 824145; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 828750; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 828750; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; ANZ Banking Group)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; AT&T CSM7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; BASA Standard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; BB55; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; BCIE6SP1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; brip1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Client Engineering 20010828; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; HEWLETT-PACKARD -- IE 5.5 SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Hewlett-Packard; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Hotbar 4.3.1.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Inovant)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Inovant; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; iOpus-I-M; YComp 5.0.8.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Q316059)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Roadrunner; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; RVQhNDHN5fHE9Vytg36u/rdyxKj6LSKTLgkNEyABZ==)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; SILSOE; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; T312461; Hewlett-Packard; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; UB1.4_IE6.0_SP1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; UB1.4_IE6.0_SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; UB1.4_IE6.0_SP1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HCJME)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Heath Park High School; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Het Net 3.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Het Net 4.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hewlett-Packard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hewlett-Packard IE5.5-SP2; Hotbar 4.1.8.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hewlett-Packard IE5.5-SP2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hewlett-Packard; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HMEUK)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HO32600; HO32501; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HomePage)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 3.0; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; Hewlett-Packard IE5.5-SP2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.2.14.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.2.4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.2.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.3.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.3.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar4.5.3.0; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hot Lingo 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hot Lingo 2.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HTMLAB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; http://InternetSupervision.com/UrlMonitor)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; http://www.pregnancycrawler.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HWT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IBP; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IBP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ICT 20021217; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; &id;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IDG.pl)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE5.5_ SP2_wOLE; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ie6dist)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE6IEAK; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE6/SEF; IE6/FO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE6 SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE6SP1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE6SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iebar; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iebar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iebar; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE_EFY)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IESFYINTL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IESFYINTL; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IESYM6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IESYM6; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IESYM6; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE UACh; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Illinois State University; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Illinois State University; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-MailBook; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; FeedEater; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; InfoCommons)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; infor INTRANET; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Installed by Symantec Package)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Installed by Symantec Package; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Internet Cafe 324)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Internet Cafe 324; ICafe 324)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; internetsupervision.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; INTRANETUSER)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; INTRANETUSER; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; Alexa Toolbar; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; PRU_IE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iPrimus)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Issued by ACC Web Services; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; istb 644; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; istb 702)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; istb 702; AskBar 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; istb 702; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ISU; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IWSS:PC-8684-ayrale; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KC135ATS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; kiev.xvand.net; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322; hunter)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; kinglothar; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KITV4.7 Wanadoo)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KITV4.7 Wanadoo; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KKman2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KKman3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KKman3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Kvaerner ASA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; L1 IE5.5 301100; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ; labs.giannone.unisannio.it; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LCAP-CB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LCPL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LDE0308a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LDE0308a),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; @lee-road.co.uk)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LendingTree.com; AIRF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LLY-EMA-EN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LM-MS; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LM-MS; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Lockheed Martin TSS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Logica 5.5 SP2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Logica 5.5 SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Loyal 4arcade.com User II)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LU)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LWC-dev)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maersk Data AS, Denmark; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Magistrat Wien)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Magistrat Wien; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Manufacturing and Customization)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Marineamt Rostock; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; Alexa Toolbar)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; MyIE2)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; MyIE2; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; (R1 1.3))" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Mazillo)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MBsdk0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MenloIE; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MISCS 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MMS Standard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Monash University (Customised IE 5.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Mozilla/4.0 (compatiable; MSIE 6.0; Windows NT; Anexsys LLC))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Mozilla/4.0 (compatible; MSIE 5.0; Debian GNU/Linux; Windows NT); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Mozilla/4.0 (compatible; MSIE 5.0; Win9x/NT; JUNO))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HDR.05.01.00.06; .NET CLR 1.0.3705; .NET CLR 1.1.4322); .NET CLR 1.1.4322))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MRA 2.5 (build 00387))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MRA 4.0 (build 00768))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; msie 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc0z)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSOCD; AtHome020; Vj2qqm9YVSwdmA06; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSOCD; AtHome021SI; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSOCD; AtHomeEN191)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSOCD; Hewlett-Packard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MTK; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; FunWebProducts)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; FunWebProducts; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; FunWebProducts; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; iebar; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; i-NavFourF)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; i-NavFourF; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; MRA 4.0 (build 00768); .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; NRTE; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Poco 0.31)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Poco 0.31; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; (R1 1.3))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; (R1 1.5))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; (R1 1.5); .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Websearch4u 2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NAB PC IE6SP1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 6.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.0.2 Final)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.0 Beta 2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.5.0 Gold)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.5.0 Gold; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.5.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 2.0.40426)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; Alexa Toolbar; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; Free Download Manager)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322) NS8/0.9.6" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322) via Avirt Gateway Server v4.2" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322) (www.proxomitron.de)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 2.0.40607; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Net M@nager V4.00 - www.vinn.com.au)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Nevada DOT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NIX)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NN5.0.4.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; N_O_K_I_A)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; N_O_K_I_A; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; N_O_K_I_A; TheFreeDictionary.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Nomad)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Nordstrom; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Nordstrom; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NoSpiesHere)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Novo Nordisk Engineering A/S)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NSWFB SOEWKS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NSW.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ntlworld v2.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NTSSVCCORP04022001-ELSAUG2001; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NZCity 6.0; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ODP links test; http://tuezilla.de/test-odp-links-agent.html)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Office of State Courts Administrator)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusIE55-27; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusIE55-31; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusNetCable-02; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusNetDSL6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Orange Development Dinges)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PAS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCM_06a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCM_06a; Hotbar 4.4.1.1381; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCM_06a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCnet Version January 2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCQuest)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PC SRP 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCUser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCUser; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCUser; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PHS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PhysEd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PIB99A)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Pierce County WA v1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Planet Internet PIM 2; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PNCStd; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PneuDraulics Inc - Rancho Cucamonga - CA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PowerGeekz Rulez; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PPI 05022002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Private information. DO NOT SHARE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Progressive Insurance; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Progressive Insurance; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Provided by Alphalink (Australia) Pty Ltd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; provided by CRC North Keilor)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PRU_IE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PsyStudentDesktop)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PVH; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PwCIE6v01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q123456)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; ADP Micro 6.0 SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Amgen.v1b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Amgen.v1b; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Amgen-v1c)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; AT&T CSM 6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; compaq; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; ESB{586E8C53-5BFC-491B-928B-AA1E0EDEC154})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; ESB{E6216221-1B63-48B0-B352-CF03FD47282F}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; HD 6.1 Custom; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Hotbar 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Hotbar 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; i-NavFourF; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; ir.ie6.v1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Marshfield Clinic)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Mind Your Own Damn Business!!!!!!)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MSIE 5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MTK; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MyIE2; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MyIE2; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.0.2728; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322; ByteMe_6969)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; ONDOWN3.2; Cox High Speed Internet Customer; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; OptusIE55-31; OptusIE501-018)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; QXW0339r; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; sbcydsl 3.12; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; SEARCHALOT.COM IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; SWFPAC NSB IE6sp1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Walsrode Online http://www.walsrode-net.de)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.0.0; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.0.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.2.6; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.2.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YPC 3.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q321064)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q321120)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QPC MegaBrowser 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QPC MegaBrowser 1.0; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QS 4.1.1.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QS 4.1.2.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QS 4.1.2.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW0333r; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03399; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW0339a; MyIE2; Maxthon; i-NavFourF; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW0339d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW0339d; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW0339h)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03411; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03413)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03416)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03416; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03417; Gruss von BURGSMUE; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.1); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.1); (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); .NET CLR 1.1.4322; SiteKiosk 5.5 Build 45; ALAMOANA2; SiteCoach 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.5); .NET CLR 1.1.4322; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RA_APAU)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RayDen)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RBC; 9LA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RC75 Release)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RC75 Release; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Reuters Global Desktop)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RHIE6SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RIS GmbH - 1.1 - A)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Roadrunner; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Rogers Hi-Speed Internet; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) RPT-HTTPClient/0.3-3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SAA; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SailBrowser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SALT 1.0.4223.1 0111 Developer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SALT 1.0.4223.4223 0111; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SALT 1.0.4613.0 0111 Developer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SALT 1.0.4613.0 0111 Developer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SALT 1.0.4613.0 0111 Developer; Search Box Toolbar 1.0b2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SBC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SBC; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SBC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.11; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; FunWebProducts; yie6_SBCDSL; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; UB1.4_IE6.0_SP1; iebar; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; yie6_SBCDSL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YPC 3.0.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YPC 3.0.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YPC 3.0.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SBC; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SCB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SDS IE6 SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SDS IE6 SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SDS IE6 SP1; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SEARCHALOT 102303)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SEARCHALOT.COM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SEARCHALOT.COM IE5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SEARCHALOT.COM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Siemens Testmanager; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SIK1.02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SIK30; FunWebProducts; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SIK30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SiteKiosk 5.5 Build 45; SiteCoach 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SKM v1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SlimBrowser [flashpeak.com]; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SLM; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Smart Explorer 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Smart Explorer v6.0 ( Evaluation Period ); Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SMSHome (http://www.aggsoft.com); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; snft internet; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; S.N.O.W.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; S.N.O.W.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; snprtz|dialno; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SOEBUILD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SPEED; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SQSW)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SRA-60-05032003; RC-60-040226)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StarBand Version 1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StarBand Version 4.0.0.2; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Steria102002; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Steria Browser - MKG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; STIE55-010209; STIE5-000710; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; STJUDE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; student.vuw.ac.nz)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.733; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.733; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.736; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.737; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.755)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.760)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.917)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.917; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; stumbleupon.com 1.924)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Supplied by blueyonder)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Supplied by Tesco.net; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sureseeker.com; iebar; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; surfEU DE M2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SURFkit V5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SWSIT; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA; ESB{F8AB14A0-3270-47A7-9717-22047C6C04E7}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA; FunWebProducts; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Systems Management Server (4-28-03))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; t20010828; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; AIRF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; BTOW V9.5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461;DI60SP1001; {1D9923A3-DFFD-4703-95E9-DB38D1421256}; DI60SP1001; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461;DI60SP1001; {1D9923A3-DFFD-4703-95E9-DB38D1421256}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Digipub,Grape; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; DonRocks; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; DSCC/DLA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; EK60SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Emf!sysUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; F-6.0SP1-20030218)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts; Hotbar 4.4.5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts-MyWay; drebaIE-ZE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts-MyWay; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; General Mills, Inc -6SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; General Mills, Inc -6SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Hewlett-Packard IE5.5-SP2; YComp 5.0.0.0; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Hotbar 4.2.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; iebar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; IE_DT2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; image_azv)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Infowalker v1.01; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; iOpus-I-M; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; istb 641; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; istb 702)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; MRA 4.0 (build 00768); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.0.3705; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.0.3705; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PC SRP 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PC SRP 2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PC SRP 2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PC SRP 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PGE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PGE; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; POIE4SP1; POIE4SP2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; POIE4SP2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PPG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Q312461; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; SBS V1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; SBS V1.1; SBS V1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; SLM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; TeomaBar 2.01; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; TTUHSC; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Tyco Electronics 01/2003)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; YComp 5.0.2.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Taunton School; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TBP_7.0_GS; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TBP_7.0_GS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TBP_7.0_GS; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TDSNET73INS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Teacher; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TELEFONICA DE ARGENTINA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Telia; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TencentTraveler )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TencentTraveler ; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TencentTraveler ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TencentTraveler ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TeomaBar 2.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TeomaBar 2.01; formsPlayer 1.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TESIEAK6a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Texas Instruments)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TheFreeDictionary.com; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; The Scots College)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TIDK)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TIETOS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T-Online Internatinal AG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TOYOTA CANADA INC.; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T-SYSTEMS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Tucows; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TUCOWS; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TUCOWS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TUCOWS; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TUCOWS; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TYCHO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Tyco Electronics 01/2003)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Tyco Electronics 01/2003; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UB1.2_IE6.0_SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UB1.4_IE6.0_SP1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UB1.4_IE6.0_SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UB1.4_IE6.0_SP1; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; University of Leicester; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; University of Limerick, Ireland; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; University of Limerick, Ireland; T312461; .NET CLR 1.1.4322) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Updated-1-22-2004)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UPS-Corporate)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UPS-Corporate; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UQconnect)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UQL Public Workstation; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UrlMonitor)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; urSQL; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; user@ch.eu.csc.com; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; %username%)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; utvi160403)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UWE Bristol; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VB_ITS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VBN; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VDOT IE6 sp1 - Landesk Package 8-2003; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Verizon Wireless 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Verizon Wireless 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VEU)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Virgilio6pc)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Vodafone España)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Vodafone España; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Vodafone; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Volkswagen of America; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VSAT500)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; V-TV Browser7.0.0.0 (Build 700))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VZ_IE6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; W2K/KW; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Wanadoo 6.1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Wanadoo 6.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; wg16)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WHCC/0.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WHCC/0.6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WHCC/0.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WODC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WRV)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.acction.com.au)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.amorosi4u.de.vu)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.amorosi4u.de.vu) (www.proxomitron.de)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.ASPSimply.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.ASPSimply.com; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.ASPSimply.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.bfsel.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.k2pdf.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.k2pdf.com; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.VanessaAmorosi.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WYETH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Wysigot 5.22; Iconico-WebTools-Pro-v1-0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; SBC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.4; Hotbar 4.4.2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.4; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.4; Supplied by Tesco.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.5; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.6; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBCDSL; sbcydsl 3.12)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBCDSL; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBCDSL; sbcydsl 3.12; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBCDSL; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC; YPC 3.0.1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.0; yplus 4.0.00d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.1; IBP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.1; yie6_SBC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.3; sbcydsl 3.12; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.3; sbcydsl 3.12; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ZDNetIndia; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ZI Imaging Corporation; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0;Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {00E372B7-BEAF-4DE2-8656-D9E207B7A868}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {00FC4ECE-55C0-4CC0-B927-A257C53EEA9B}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {010372B4-6664-4F0F-9F72-69CDEAAEF34C}; SV1; sensis; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {01CCA09B-D5C0-494F-9AB2-C6A542FB3229}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {02E74E79-2624-4118-ACC0-B2B5E3303175}; SV1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {04C71239-93BC-463E-8049-E98C6347C7B6}; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {05292C4C-2C29-4A29-A4A3-07773831343F}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {059455F9-7AF0-4213-B2BF-552E61CC057A}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0840790C-3719-4A4D-95C6-1C8D668C09FB}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {096DD935-8F09-400D-862E-BAB1224F8D8B}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0A4A867A-C305-4125-BDE0-9596EAE3F231}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0A6E773D-A7D9-4536-BA0E-85BC13B3537F}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0A9BDEB0-929E-4F14-B6C5-EEF41B896043})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0AB53206-6DD9-450D-B4AA-685C7E5148B6}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0AB63054-8A7C-42DB-BFD8-DCBDA1D57B67}; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0DC2355B-02C9-42D8-9358-7CC385381704})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0F233567-886D-460E-BCD2-88171D6F8C04}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {10D39F67-2519-4768-A71A-9F7915E2CABE}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {11C208DD-B1E1-49F3-A67C-2E8F81A0450E}; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1&1 Internet AG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1.21.2 ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1272B23E-8FD1-4BBE-A149-41B4E94621EA})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1.41.1 ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {150A8501-CEA4-4B5F-A7C9-55616EDF8F6C}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {154813CD-3783-458E-B7E0-3294360CA69E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1.56.1 )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1.57.1 )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1639F6BF-2F23-4A84-AB07-B2FC5A94935A}; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1681F45C-A0AD-4298-922C-5469DF1CB2EB}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {16A0E5E0-30C1-4ACA-AB32-0719A8E952AA})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {17156865-D8E3-4E6C-B430-78B89BA7C978}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {177ECE14-992D-4AA3-894B-5071AFBC00D5}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {18154988-E91C-4941-B5B6-4FD487BC0525}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {18C2BD69-EEEF-4151-BBA4-23B98B4B6B03}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1903CC58-2135-4245-A3C4-C539A1B2F880}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1907B553-57F7-4A6E-870A-C4744E1B6316}; iebar; CustomExchangeBrowser; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1A29EBB4-B546-4452-A5BE-BECD78E4775F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1C)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1DD69613-6D5A-4E27-862B-7CD98B580F7A}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1E96F9A7-2DD2-4386-8EB8-7D4B33840A98}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1ngo!)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 20040404; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2085FE1A-3A52-4263-9403-CB8938637154}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {22311735-7766-4562-8318-CFBA42C160AD}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {22827DFF-8DEE-4B06-A2D8-42D90E0D53CA})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {23320F0D-2CA6-4BB2-B889-E23EDE240004}; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {23521C6A-ECC2-4461-B2D4-9D9C390B90F0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {24886906-C12D-4D24-8A85-046283E20B25}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {26335003-5381-431D-85FC-5FBAE901B682}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {28267C2F-1F37-4133-A363-3AE7FE96A5ED}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {284FBE28-A81E-404D-AF29-EDD0384E1E1F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 2919; 21231; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2C003D7B-598B-0DEA-1120-FD31003AE559})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2C283092-4E93-4C58-ABE1-07EC5031F0D5}; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2D23B066-4320-4A33-97E2-37D1E986227E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2D25856C-B035-4C44-A548-A4A90CFF8355}; ESB{0F85F697-7BE6-4024-9936-09124BD6C11D}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2EC67C21-DA69-496A-A8A2-C518BF746B76}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2F11EBA2-D79D-47CE-8038-E25C5C60CA50})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2FD51919-0611-4405-A0C0-2B0757909879}; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 2XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3043E601-196A-4FD7-89B3-30B82C26D3D1}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {32097A18-1D85-423C-913C-A7BFACBE9070}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3277AD62-7541-4E08-85FC-9058C62AFB67}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {328DDFC1-1867-4044-B118-01E6C8878FA6})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3304)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3305)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3305; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3328C095-323C-45D5-8C47-94D927422276})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {341A244C-4429-403A-953F-332E6B717C94}; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3463A193-AB0F-48A2-A40F-314E277D4FA8}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {35466D8B-0733-4318-9C15-90D01F7D18B4}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {35A6C8BC-4D10-464E-9059-0786612B0949}; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {35DE4964-76A5-4C61-A6C1-12ADF40CF932})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {360D7714-1669-40B4-8A79-8DC66280E427}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {364EDA13-8707-497D-8D19-043EC47F06E9}; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {366089E4-4B15-4161-81BD-0BE380E6C054}; urSQL; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {387DAA29-45E7-4360-9D07-3C17CEF67768}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3A536119-BE87-47FE-A2CA-00EC28725F68}; SV1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3A584A4D-518C-4D0E-BC6B-541B7D69A3FE})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3CB6D22A-827A-4D5B-95D1-C25042B282C6}; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3D309697-A650-4F70-9E8B-3E5BBD8136D4}; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3F766A6E-FF5A-419A-8E0D-B410CC976848}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3FD99CE8-4876-42EB-A98E-C3240840E16F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3M/MSIE 5.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3M/MSIE 5.5; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {40BEA18B-3AD4-4A88-87CB-9F3E34B672C5})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {41D06DE4-3B47-4AFE-8586-A2A0BC21128B}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {42662884-5207-488E-88DD-22D1EE5876E4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {438A4A73-BC8A-4815-81F7-E684646FE3BB}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4489F513-F2F4-428D-862D-E328E98846C1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {474A61B2-06FD-4AC4-BD58-15A5EE8D135A}; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {48B30A43-F85C-421C-B89F-5D8DCE6F0C33})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {48BC54DC-03AC-43C8-98C3-6C74FAFA4CBF})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4907EF1F-C744-4C7A-BD93-DB6598A4124F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4910F99D-049A-4B1E-AA4C-6254837DE90E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {497D41FB-CBB2-4214-A8FA-2C8339E15215}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4D0F642B-7758-4DD7-806D-22F5C327491B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4DAD8D3C-DBF0-48FF-81D9-D8B6056B250A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4F0AA017-AB3E-4B63-94AC-3554E6E79E2B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {505431EF-B36F-4113-AD87-A9F319C9A9A7})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {505F1043-8A30-492E-A1F4-6D76A19DAFDC}; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {51B5AE33-C14D-49E0-B977-C367563556E8})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {52370F31-7911-CA01-5788-3A30A77F2822})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {53810FCF-D003-454B-BE56-53B2FCF44FD9}; www.kpas.net; IBP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {55173041-4495-432A-B14A-DC8C4904669C}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {55173041-4495-432A-B14A-DC8C4904669C}; .NET CLR 1.0.3705; .NET CLR 1.1.4322; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5677AA33-67A1-4270-B68D-B5D5A4E95FA0}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {56B378DE-DAA6-4681-9973-9BEF2D4DDC6F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {56CD5059-BD0C-4315-9677-6D1C92EAF5A8}; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {56FA8E7E-12AB-4911-A191-21C37C311D65}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {581A1CD1-357D-4B8D-8953-C522246CC007}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {581CB45E-7FDC-4B9A-B71C-28266E860749})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {59632201-F778-4CBA-B1F4-C4CCD491D964}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5B643202-DEAC-4D35-BC57-FE4279576E94})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5C2F722D-C130-4AD3-8A07-5D3C659A6926}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5C405188-4130-4F5D-801B-92844913257D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5CD38EE8-DD84-47A1-9FD8-61C91D812942}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5D6BCA52-DC20-46F7-B828-2B34BB4618F9}; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5DF11A3C-26FC-451E-9C44-151B22E63F64}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 601-24)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6240A551-23EB-402C-8A79-008063B05AC2}; Alexa Toolbar; Feat Ext 18)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {625B82F8-3C54-4C68-B502-9EDAD5E5A2B0}; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {654B0711-4A85-42E7-983F-7C17305D0E48}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {66830790-BB7A-4162-B58C-8A914A9DFF5C}; SV1; 1.57.1 ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {671249BD-E4C8-4962-8F4C-B5116D567611}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {67198D79-41B9-4775-88C5-FF11BF28DF6E}; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {676CA98F-335D-4002-AE68-06EC0FCD863E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {68070A19-8A16-4631-9EC8-4A06D22F83A6}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6A5F8282-BD7B-4C03-AA47-D5EA5EE6CC2C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6A7ABDFC-3C88-42D6-8E5C-464935051D13})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6B03FCEC-E168-4CD2-946B-4E7C3171D66C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6BC3FAAA-4F70-42A4-A3D9-5D6E7D38B6E6}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6BD7D868-97D7-4021-A0D1-AFAFDE7AED4A}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6BE32F1D-C93D-4A7A-AB49-C6C28663C805}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6C4A00C9-0682-4A2B-A5C5-7C066461D41A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6C54EE4C-5F00-4EEB-AABA-A35C734E2654})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6D2550C2-E7EC-4A02-84F9-AE5DA7671170}; SV1; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6D733935-1BA5-402C-81CD-EFFD0A66928B}; SV1; OptusNetDSL6; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6FC0CBD9-8501-A7A3-BC23-9E828B1739DD})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7029D658-033C-4F21-9334-3028D54A9C46}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {70A105A4-3B56-40B8-ACB3-0B9567712A0C}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7166AA8D-9F2D-45AF-BC84-3A13C84AB68C}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {716A884C-2833-41B9-B4A2-7CFF5CC19774}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {725986B4-361D-4262-888A-1DEF1D40A677}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7275A900-6883-4F2C-9D7B-9D7E6F1B1CAD}; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {73031379-6EF6-48A2-8182-5E04CA2B100D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {73CA2DB1-3D3A-4AA3-BE60-1AB52BBA5DC7})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {73FC897C-EB65-481A-9DFE-D5E6BA3549EF}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {746BDD15-B60E-45F9-8D9B-0DDBC59E6A16}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7564D434-679A-406F-BB78-7277EA46547A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7609500E-F1F7-4395-AD02-DA8F288385DB}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {76558216-F653-405A-BD95-00857C519BFB})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {76CBD2B2-30E1-4D85-BD1B-D854AEB6FC5B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {76D1A158-5E58-4876-B3B5-09A18AF2D3AB}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {773D9899-3378-495E-AC5D-D9489250EB13})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {776316A7-FEC1-44A8-9DB5-8469FF21105D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {77820B37-7295-47CD-8842-0AA10651F383}; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {79D3BB58-8001-4C11-BB86-ADE061CEAF25})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7A834B30-AA9D-4D2B-AC38-919CE48D56E2})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7AAD7328-EFD7-4E69-8B69-7E9E6D5F4B2F}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7DABAE32-5850-47DE-A886-7BF64850D96D}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7DCFFE58-FF03-4A2A-B3E6-8149BB0EF19F}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7F82049C-378B-4A5A-98D6-E1D43E43CFA0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7FB10817-27B8-4D7C-86DD-C61DFD37585B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {80351674-652B-4DDA-8432-41F8E61AB1E7})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {82EFCD46-30E8-45E3-99B6-AD90BEBDAD6B}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {835E8FC0-7916-4D1F-AA80-DD7F553053C6}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8421A6E1-44C8-4B7D-A950-5EDE1F3181F0}; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {85192DB1-086A-4E53-A59F-BDB83377709A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {858921CC-D456-4230-95D4-B968432409B3})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8590B1C5-F4E9-41B0-A990-A8C325015392}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8621CC8A-4F10-45B1-9C16-A289C29FB98E}; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {865C266F-BCAE-421B-BF88-F1B120A4F943}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {88516849-FDAF-4A0A-956F-FA2CF2F6D7F9}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {888CC72D-0C51-4514-9AA7-507E9D2D6A9E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {89E40FF4-BD77-4586-B092-EB6957FFEEC0}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8F1D0313-7282-4B1C-B38B-E33B59B2B5B8}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8F8DADE0-9F1C-406B-8D45-A3686358668D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {906090F7-10E4-4B25-B2D9-D258E722AFC4}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {913B3453-254F-4FC2-AB37-B3CB009590D0}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9520EB69-95A9-4B9E-B576-F9453174C6F8}; ESB{C8AD18A8-BC88-40E8-97D9-31784C41F582}; ESB{50D170B2-6884-4234-96B4-22273E912859})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {965166C4-481A-4D30-8597-0A4319911257}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 97828)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {97D5F745-44A2-4093-B7E1-E8235862D1CA}; SV1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {996DA28F-748C-4439-ABC3-4546531ED0FC})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9AA7FFB2-7E7D-4B92-86AE-835F7B135CB9}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9AFC0F21-2679-4207-98D7-E2DB9CDC0E89})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9B8F54EC-CC98-489C-9050-D61EF01E6D45})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9C3408B0-029E-479E-93AD-AA8492C083CE})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9CD98633-D53A-4916-B25D-BBF0EC6299A5}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9CD98633-D53A-4916-B25D-BBF0EC6299A5}; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9CE63974-BFE2-4797-BEB8-B8C133A401B9}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9E70E38E-EEFE-48E4-9B4C-BF0FEE5E94CD}; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9FE37218-F0B4-43AA-8528-2B052E647F3C}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A159BA28-48C0-4189-BEE6-D59494BCDD76})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A27C75DF-D29F-4B21-834D-66C1B23297E5})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A2841CE9-E06C-4BB2-AF6B-14C4EAA0F0CF}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A333877C-5AE7-4532-969B-A6004713EF80}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A4E5458B-4CE1-4552-9D0E-8C01D102C7FA}; FunWebProducts; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A5891798-8194-4EC2-BB31-8C33151147C0}; ESB{9E677553-0D9B-4A40-B6E7-8AD691A3065F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A61CE854-3B32-4B71-B3BD-60DCE467E30E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A88CFFCD-C389-47D6-8AEC-52C1DB0371C4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A97D2399-C6DD-47F7-A9E3-4C2842744510}; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A9D3BF59-505F-4316-AA7F-ABC49BF4B03E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AAPT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AAPT; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AAPT; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {ABC49948-9942-404D-B4FE-574FCA90475D}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ACSWorld; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; actually Firefox - assholes, support Mozilla/5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ADP Plaza - Build 64; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {AE17F330-EBBA-4B78-B5DF-3288211BACB4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {AE480139-C1AA-4168-9BA2-24E090FBB8C7}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WILDdesigns; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; Q312461; SV1; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AKH Wien; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Al Asad/Hunter Site, LSA Anaconda; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alexa Toolbar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alexa Toolbar; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alexa Toolbar; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alisys_ONO; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ALPHA/06)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ALPHA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; anna mielec tani seks dziwka; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ANONYMOUS; Huntingtower [INTRANET ONLY]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AOL7; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; OptusIE501-018; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APC; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APU-XP; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Arcor 2.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Arcor 2.0; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Arcor Online 3.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 2.11; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; .NET CLR 1.1.4322; Fluffi Bot+)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; SV1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskJPBar 3.00; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskJPBar 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome021SI; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome021SI; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome033)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome033; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome033; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome033; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome033; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHomeEN191)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ATOM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM 6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM 6.0; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM 6.0; YComp 5.0.2.6; FunWebProducts; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM 6; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM 6; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM8.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc11; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Q312461; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Q312461; SV1; .NET CLR 1.1.4322; MSN 9.0; MSNbQ001; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Roadrunner; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM 6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM 6; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; FunWebProducts; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; .NET CLR 1.1.4322; Feat Ext 13)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM8.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T WNS5.2; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T WNS5.2; Q312461; AT&T CSM6.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; austarnet_2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; Alexa Toolbar)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; FunWebProducts-MyWay)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; MyIE2; Feedreader; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; MyIE2; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; SV1)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; SV1; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Awe¤6 - Adonay Web Explorer; Mozilla/4.0 (compatible; Awe¤6 - Adonay Web Explorer); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B0832C32-9DEE-429D-9138-56DD764E4C9E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B2570479-25DA-7559-C478-C0A0855A6BD5}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B3215A47-A5E1-4B6A-9BB4-3DF0A424B6A1}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B473E576-6FFF-4F71-9FE5-29224CE32692})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B8106019-1D23-4C8E-808C-AE28616B449A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B9554770-CEA1-4514-BC49-A30D9169404D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B98C23CE-0A06-492A-A248-BF4336DE4EDD})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BB B500 U2.02; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {BBD40907-B7C9-4947-9B8F-A62A288A98F9}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BB-INTRA-MAI2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BBT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; MathPlayer 2.0; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; Q312461; SV1; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; SV1; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; SV1; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCIE6SP1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {BD0F71D8-0AC0-49F7-BD87-81F5C24E60E3})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {BF2D4BA4-80A1-46E5-AC3F-B62AED59596C}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {BF8B323E-06A3-459F-BAB5-ABE8401D417A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; bgft)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BIGPOND_ADSL_42; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BIGPOND_ADSL_42; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BizLink; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; bmi ecommerce; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; bpc; SV1; (R1 1.3); (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BP E1.06; SV1; Smart Explorer 6.1; 1.41.1 ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BPH32_56; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BRA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Brew_Browser_6.0_SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; brip1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; brip1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; brip1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; brip1; SV1; Sidewinder 1.0; formsPlayer 2.0; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .: BritishHeaven.de :.; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT [build 60A]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Business Broadband; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTinternet V8.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTinternet V8.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTinternet V8.4; YComp 5.0.2.6; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTinternet V8.4; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; AIRF; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB; SV1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB; YPC 3.0.0; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB; YPC 3.0.2; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld Broadband)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld Broadband; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld Broadband; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld Broadband; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTOW)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTOW; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTOW V9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTOW V9.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTT V3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BWCH30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C122D12A-1212-49C3-89B0-CD9F3ED9F7BD}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C1B43645-698E-4524-9042-76FC08FDE51A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C2EED8D4-0E69-4BC2-8F34-3B246690F6DE}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C389C776-89D8-4251-A003-AC55DE5E6821}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C429A6DA-4192-4DD9-85EA-B5EC7CB4DA25}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C5D1D9A9-F1A0-4C62-8162-8BA0DD8C3BA4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C67ED323-27F6-4127-B7F2-56691D7AC32F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C713E123-6F1C-41FC-84B3-880D9608E8D7}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {Cablevision Optimum Online}; (R1 1.3); Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CASPERXP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CASPERXP; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CASPERXP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {CD23D801-AD49-4451-BCEE-0E1BBFC3E71A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=ALLIED_01_01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=ALLIED_01_01; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=ALLIED_01_01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=ALLIED_01_01; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=BP1b.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=BP1b.00; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=BP1b.00; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=storecd_01_03; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v11c.01; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v12a.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v13b.06; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDsource=v2.15e.03)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v3.12a.00; SV1; YPC 3.0.2; yplus 4.3.02b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.01; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.03; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.05)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.05; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.05; NN5.0.2.12; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.05; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.07)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=vBB1c.00; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {CE4189CF-B7E9-4F85-B301-6CC3C11A0196}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {CEDA55FF-C15E-4879-88A3-A83B90CAFEC5}; MCI Windows Corporate Image; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; :certegy Corporate; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Charlestown; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Charter B1; FunWebProducts; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Charter B1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Charter B1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CHWIE_NL70; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CHWIE_NO60; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CHWIE_NO70; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CHWIE_SE70; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CITGO09302002; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cng)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CNnet Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; COE June 03, 2002; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; COE June 03, 2002; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; College of Business Administration Lab; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; COM+ 1.0.2204)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; compaq; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; compaq; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; compaq; YPC 3.0.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Compatible; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; @; Compatible; Version; Platform)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Compatible; Version; Platform)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Connect 1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Consorzio Operativo Gruppo MPS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; consumer; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Corporate Image; MCI Windows Corporate Image; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cox High Speed Internet Customer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cox High Speed Internet Customer; Hotbar 4.2.8.0; Hotbar 4.3.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cox High Speed Internet Customer; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cox High Speed Internet Customer; Q312461; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cox High Speed Internet Customer; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CP; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CP; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CPT-IE401SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CPT-IE401SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CPT-IE401SP1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CPWR)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CPWR; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; ESB{AE9445A2-0ED0-4AC0-BDE4-3EA933008624}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; Hotbar 4.4.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crick Enhanced; Q312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {CSC})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {CSC}; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CSIE60SP01; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CS.v0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CursorZone 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CustomExchangeBrowser; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Customized by Computer West; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CVnet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CWCRDAY; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D009E04F-7285-4277-BAF6-77797A8417CF})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D03E5946-02C5-4FFB-BDF7-A2D658A27777})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D15E0797-FD3B-413C-B67B-63D937268BE0}; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D1F76FF8-EE02-4E7F-BB77-5D6682CC4F46}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D2C0EFBA-26D7-48B4-8500-1F2483B6044C}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D379CF0A-4B77-463F-B99C-6E854BEACF65}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D546DB1D-E98F-468A-8876-49573C986A27}; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D72714F6-A809-4DE6-B422-2B2ADCEBF152}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DAgroupPLC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DATASIEL; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DB056177-05D3-45EF-A868-F029A67735C0}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DBF8B407-FE31-4D86-8C6E-2F831D79AB5B}; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DC6A17BE-3A95-4B92-8292-A8EE80FB04CB})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DCAEF9CE-8251-422E-ADD0-AD2B56DEFED3})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dcdev001; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DCSI; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DD7B8EB4-6D8A-46BB-B262-45CEC0C799E8})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DDnDD; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer 1.3.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DesignLinks; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DFD18BB5-E42B-42DE-9F12-A936648D0AF1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DFO-MPO Internet Explorer 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DGD (AutoProxy4); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; -D-H1-MS318089; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; -D-H1-MS318089; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DI60SP1001; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Dialer/1.10/ADSL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Dialer/1.10/ADSL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Dialer/2.08/Frisurf; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial; NetCaptor 7.0 Beta 2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial; SV1; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial; SV1; www.ASPSimply.com; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Assistant 1.0.2.4; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; FunWebProducts; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; KITV4.7 Wanadoo)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; NN4.2.0.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Q312461; iOpus-I-M; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Q312461; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; SV1; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; VNIE60; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; VNIE MESH_PC; YPC 3.0.2; yplus 4.4.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; YPC 3.0.2; yplus 4.3.02b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; digit_may2002; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; digit_may2002; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Distance Learning, Inc.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; D-M1-MSSP1; D-M1-200309AC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dna Internet; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DOJ3jx7bf; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DOJ3jx7bf; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DownloadSpeed; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DP1000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dpx; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; drebaIE-ZE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DrKW; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DRS_E)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DRS_E; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DRS;Techcom Software Solutions Inc.;KDDS1277;IE6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; d:tnt7_ForumBrowser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; d:tnt7_ForumBrowser; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DVD Owner; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E2B5FAFC-1899-497E-BACC-EEEA7F24A5D2}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E2E07F6D-A6E7-1684-82DA-8DE003B9C217})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E422A9F3-43BA-41E7-AF5D-838A15EBE348}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E4BBB50E-5B1B-4D8C-A819-AD524233897E}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E5E08788-0480-4269-BC71-A7797C5D3C62}; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E69CE46B-FC60-6F41-B5CD-7789712032EA}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E85C6A09-3F78-4078-B300-293C2CD8FD03})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E875708F-E195-B824-10FE-6BB954D80082})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {EA1C7663-ACC4-45B1-8A90-221B12478AF0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {ED79526B-0CE1-4925-AAFF-F8C063DE0161})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {EE8C6E6D-7C14-493D-96D8-96189CDB443C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {EEF090D2-AD10-4793-AA02-7C5F2B8F099F}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {EFACCBB9-0BDC-4B3A-A7B9-051398D9E119})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; eircom/june2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; EJGVNET; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; EK60SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; EMC IS 55; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Emiliano ti vede ....)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) [en]" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ENGINE; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; EROLS040199)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{02508E72-8688-4F8C-BF9C-73C3D029563C}; SV1; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{101D66DC-5446-428D-A6EA-ED273C9FC84B}; Hotbar 4.4.7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{10ED3712-AD0D-4BB1-8D3C-0B0E15A671C4}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{1234D1DF-0277-4F9A-A0EB-0FAF5D432EE2}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{133E6249-80BF-4741-9A39-10C8D7C998AC}; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{136B3929-78D3-4728-A726-73ECC4B983CF})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{180F232C-E374-4B08-A664-FA09F726DBE4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{1C38363F-253A-4424-B102-4495048AF33E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{28878E88-F98C-4A17-878A-E36A996D5072}; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{2F39423D-9DBB-48B9-B343-20ACBF9CFDC2}; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{30E3976E-D14C-4C93-B9B7-9AFECD8F306F}; MyIE2; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{31889988-FC07-40BA-7F3E-AEBEA15391D6}; ESB{E2E93F3B-0BE5-472F-2ABB-1C9AEFB49813}; ESB{CC56F89D-FD35-4E39-6074-F0B433D7D482}; ESB{225AAA31-E92C-4034-89D0-14B9F20BE982}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{34824601-AC35-488E-B249-BCD4AAF8A1C6})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{35404506-8A98-49E1-9E17-D61E2C1BAC18})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{3D72EE78-2FEB-4C75-B8DC-3BF40C60D3C5})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{45F63CFC-FA29-4C6E-A6D6-B947491001C8}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{472D70C9-7893-4D2B-B119-BB44221294EC}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{4779B872-DBEE-40A8-8442-E0FF5DA484D7}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{484F9004-564C-4B12-AC4E-1418ECDE928A}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{4B268CB2-51FA-4C84-B624-6DE3F0D887DA}; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{4D3EA7A9-3801-4A63-91E9-5CCC71E6868C}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{4E071CF0-5E40-4332-8E3D-AF6371997B08}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{58553345-1609-429A-8ED6-D9F1B9A77DC2}; ESB{65E1A955-DCEC-465A-821C-54F40FF8B34A}; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{5D811861-EA95-45EE-B290-38265CDC5E35}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{62965017-4DF0-4965-87E8-BA0D8449C3DE})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{688258C8-E4A8-482F-9667-C29B4CABFA9A}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{68DE235B-522D-4012-A9D9-E5F196997BC0}; ESB{D7EC4F6C-EFE4-4DBB-A0BD-FFCA2CEF6E60})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{6AF1F99B-2A01-4167-B3EE-BC497D63F9D4}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{6EFB5336-7A45-448B-843F-9AC66EF6FBD1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{73AE67D7-E15F-4325-B51F-124AB9646A23}; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{75618962-1051-4901-83E3-FA45F0DE1ADD})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{75E350B6-0105-4218-971A-A1CB090DC683}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{77A48D0F-61AF-44B4-BEFD-42E758642C6D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{7D07736D-DE37-4F7F-AC8E-C68237EBF022}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{7F8B060C-274D-4956-B4B4-46DEFBCBF28A}; ESB{4B5E3CE7-C53E-4C53-A2EE-6D064498DF1F}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{82EA8C84-7DC3-489C-B779-A3469BE4708E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{83E1DA4B-9DEF-4AFB-883B-D347E5A6107D}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{87F2D8B2-4248-4885-A012-C7B7FA26F488})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{8C127829-44A0-4BB8-9D28-E81994F66EE0}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{8C9138AB-F2ED-4BB7-A14E-2A3D3D977E0B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{91E7C142-4F0C-49FA-81C3-1E8A6C52A2F3}; ESB{C50C0A96-9BEB-46E8-B245-4EC5EC3830E5}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{9981848E-AAB6-4A05-B8A4-3A0A5F328952}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{9B524756-DEC6-4F01-8E9F-5922E7097A74}; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{9C041F81-CD5B-4241-9C74-CD4FE075546E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{A1F633C5-98D0-4F80-A38A-7A216501394C}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{A5C6ECFC-8673-444F-B7E7-DE0C5B59D622}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{ABA66D21-29BE-4BAF-BAD4-ED6812C1E033}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{ADA09EE9-2082-4E60-A551-973A98214068})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{B485C8BD-00D2-42A3-A424-90D47ECB16EA}; ESB{51D3AFB9-B34E-42EB-8AD7-D60D7CEF84E2}; ESB{B901E2E3-3130-4FD3-A611-F671E4D7D235}; ESB{F8ED9EF0-B332-437D-AF6F-E4D7929AAE51}; ESB{145C6EA3-68A6-4840-8583-FDE74" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{BC8D007D-0F64-48DF-9841-D9A5F8184B58}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{C48545AB-77DE-4E4E-AC5B-183794002D5B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{C809320D-9E35-41B8-B589-1857D6C6B121}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{C9452703-6C32-4564-9A1C-E11A31A69CD4}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{CD23C4DA-697C-4A7E-B50B-884DD2A1A8E2}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{D65EE013-85EB-431B-A47F-633C4457E9BE})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{D6E592CA-A859-4145-A375-64AC4DFC291D}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{D8F6BF12-200C-466E-85E5-06BBD005995E}; YPC 3.0.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{E3E1E7D6-9A2C-4F39-843E-362AB50F6088}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{E63A7B5D-0538-4B3D-BBAB-915D834B1FE3})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{E6DD635D-0921-4491-B013-17AF67B2E602}; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{EA155034-249E-47E4-988B-5576EA36F928}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{EA67BD1B-D57E-4131-BCEC-E5C35BD6A0CE}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{F0F896A7-E6EA-4914-B1DE-C16BBB4A67E1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{F40811EE-DF17-4BC9-8785-B362ABF34098}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{F7A8BDDE-BB37-40C8-AA1D-4B57BD78EFBA}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{FE364DB1-9712-443D-8511-83A85984644A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{FF0BE471-F8FA-4219-8FFC-07515C5FCB9C}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Eurobell Internet; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; exNetPanel:1059240)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F1ECC819-455A-46BC-A405-EFB52BF85707}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F2024F27-DA75-4D6A-B590-2AD23305F9F7}; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F27B2FF4-5121-47B1-8A63-CE5BD1021640})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F29D822D-EED0-4E29-8B61-8B038CEC1C0A}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F35D706E-FD32-451F-9A2F-DFD96F9F0DA6})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F3A9F2D1-57F6-4A32-8E00-5AA391FC89A2})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F467C9A2-D4AF-4B0F-890E-8F8923BAE9C2}; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F4E70CE0-6237-4227-906E-788A750F9FB4}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; F-6.0SP1-20030218)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; F-6.0SP1-20030218; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F70A8590-C5BA-483C-BE5F-8589C20E9B38})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F7BF8B53-70AB-4EA6-915C-C70769C62210})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F8498490-1D66-4D29-9FCC-BB35327A6257}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F8FE05B9-FCEF-4302-AC51-C4B61FFBF4B9})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FA63D7BD-846C-43EE-9287-0FB9150B1111}; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FB15F932-A469-4646-BCB4-8EB15AECFF9F}; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FC1AC744-B5CC-4237-96AA-E63B9FE6FE44})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FD749AFA-79D4-49DF-9348-6228D25835C8})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FE8FFD49-3EE4-412F-B700-175757E8EA1B}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feat Ext 20)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FEB_2004-TPG; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feedreader; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feedreader; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FF25C218-3C07-491B-BFCA-D6C5557A414F}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FF360BD3-4648-4D2D-94C7-F95404BDC9BB})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FF8CB3A2-81BE-4550-B98C-CC9DFAF7A452}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FF8CB3A2-81BE-4550-B98C-CC9DFAF7A452}; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FFBF6A73-2389-4D4F-A470-862760ED16CD}; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FGL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FIDUCIA IT AG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FIPID-{6/j.Ss94W0oM{6KchRpCsLmMQ222656249)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; fisg IE 6.0 SP1 (FID r2.0); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FMRCo cfg. 6.01.3.1b1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FMRCo cfg. 6.01.3.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FORSCOM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Free Download Manager)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; FunWebProducts) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; SV1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FreeWeb Explorer 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FS_COMPAQ_IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; fs_ie5_04_2000_preload)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; fuck you; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; AskBar 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; BCD2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; dial; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; ESB{27845BE7-0EC6-473C-8064-3C4A063AB585}; ESB{5CEF3C99-0C80-47FB-B591-9EA0568D728D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; FIPID-{8ORj5ZKEvfbg{8r02nwzw7eKE181427001)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; FunWebProducts-MyWay; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; FunWebProducts-MyWay; Wanadoo 6.1; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Grip Toolbar 2.07)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.3.5.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.1.0; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.2.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0; MSN 8.0; MSN 8.5; MSNbBBYZ; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.5.1.0; MSN 6.1; MSNbMSFT; MSNmen-nz; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.5.1.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar4.5.2.0; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar4.5.3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar4.5.3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; HTMLAB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; IBP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; iebar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; iebar; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; KKman2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Maxthon; FREE)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmsv-se; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 8.0; MSN 8.5; MSNbVZ02; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyTotalSearch)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyTotalSearch; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyTotalSearch; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; ESB{285EDB64-F0D5-40CE-9E80-0424E454F7A4}; ESB{82D87D6A-A9EA-4A92-A8E0-46F5501A1E54}; ESB{53A21F9E-0210-412D-A05D-A8145EBD094A}; ESB{B709ECE9-AE61-48D0-8788-FBBAD5FECB3E}; ESB{829700D" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; Grip Toolbar 2.07a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; JyxoToolbar1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; NetCaptor 6.5.0B6; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.0.3705; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; OptusNetDSL6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; www.kpas.net; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; OZHARLIT5.5_1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; PP; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Preload_01_07; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Primus-AOL; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; ESB{793F2EFD-3EE8-4B36-AB38-1853C6EC257E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; Hotbar4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; Maxthon; MediaPilot; MediaPilotAd; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; Maxthon; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; MSN 6.1; MSNbDELL; MSNmen-us; MSNc22; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; snprtz|T04114572010350)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; son-OEM-1101; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; YPC 3.2.0; .NET CLR 1.1.4322; PeoplePal 3.0; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; YPC 3.0.1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FVSD#52)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; [Gecko])" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; generic_01_01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; generic_01_01; FunWebProducts; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; generic_01_01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; generic_01_01; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE5.5 SP1 4-20-2001 DMG Build)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE6.0 Build 20030604; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE6.0 Build 20031007; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE6.0 Build 20031008; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE6.0 Build 20031008; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE6.0 Build 20031111; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE 6.0 Build 20040714; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Global Visioneers, LLC - www.GlobalVisioneers.com -; Globcal Visioneers, LLC - www.GlobalVisioneers.com -)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GMX AG by USt; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GoldenWeb.it)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Googlebot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Googlebot/2.1 (+http://www.googlebot.com/bot.html))" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Googlebot/2.1 (+http://www.googlebot.com/bot.html); Maxthon; FDM)" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Google-TR-1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; H010818; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; H010818; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; H010818; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HCI0430; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HCI0441; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Headline-Reader; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Het Net 3.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hewlett-Packard; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hewlett-Packard; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HinBox 0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HJS.NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; hlink5.5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.7.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; SV1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.10.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.11.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.1.1281; MSN 6.1; MSNbMSFT; MSNmfr-fr; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.1.1367; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.1.1367; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.13.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.13.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.14.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.14.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.8.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.8.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.1.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.5.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.1.1394)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.1.1394; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.1.1406; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.4.1.1415)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.4.1.1415; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; FunWebProducts; MSN 6.1; MSNbDELL; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; FunWebProducts-MyWay; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.7.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.7.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.0.0; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.0.0; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.1.0; .NET CLR 1.1.4322; FDM; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.1.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.1.0; SV1; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.5.3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.5.3.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar Unknown; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hot Lingo 2.0; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HPC Factor; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HTMLAB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HTMLAB; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; hubbabubba)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HW-IE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IBP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IBP; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IBP; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IBP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Ibrowse/3.2(Ibrowse3.2;AmigaOS4.0); SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Icewtr Network services (jen); SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICLP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICM60)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICM60; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICSLabs - USC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICT; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IDG.pl)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE5.x/Winxx/EZN/xx; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.05; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE60BRMM by STASM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 (FID r1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 (FID r2.0))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 (FID r2.0); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 (FID r3.0); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 (FID r3.0); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 (FID r3.0); (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 Unrestricted; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE6CFG32a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE6CFG32a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE6SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; DP Oslo; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-in; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IESYM6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IgwanaBrowser; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; Feedreader; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; Feedreader; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.1.4322; FB-Solutions)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IncoNet Starter Kit ver 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; INFINOLOGY CORP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; INFOAVE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; INFOAVE5; Q312461; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; INFOAVE5; Q312461; SV1; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Infowalker v1.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Infowalker v1.01; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; INTDUN; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; brip1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; Free Download Manager)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; Maxthon; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; MyIE2; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; IBP; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; MathPlayer 2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-BLD03-PRE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-BLD03-PRE; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-BLD03; SV1; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-CMPQ-2003; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-CMPQ-HDD; FunWebProducts; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-CMPQ-HDD; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ip_internal_request; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iPrimus)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iRider 2.07.0018; SV1; Feedreader; .NET CLR 1.1.4322)" + family: "iRider" + major: '2' + minor: '07' + patch: '0018' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; isp1057; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; istb 702)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; istb 702; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ITS-Ver1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IWSS:MSC01048/00096b3da0d3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IWSS:SPH-XP-SACH02/0008a1091f37; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IWSS:WXP4390/00904b631249; IWSS:WXP4390/000d567960f4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JackGTestLocalMachineValue; someFunkyString; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Others)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JAS; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JLC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JMV)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JMV; SV1; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1);JTB:15:817d2be2-fc1c-4568-8f4e-cc5f9a982e3b" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Juni)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JUNO; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JyxoToolbar1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JyxoToolbar1.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JyxoToolbar1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JyxoToolbar1.0; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Katiesoft 7; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KITXP40NL; MSN 6.1; MSNbMSFT; MSNmnl-nl; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KKman2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KKman2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KKman3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Kmart; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Kmart; Q312461; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KPMG; InstantAlbert; XBOXToolbar; CustomToobar.com; Eduardo A. Morcillo; Custom Browser Inc.; SavantMedia; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KPMG; InstantAlbert; XBOXToolbar; CustomToobar.com; Eduardo A. Morcillo; Custom Browser Inc.; SavantMedia; SinglesToolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KPSWorkstation; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; LDS Church)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; LIB Staff; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Link Checker Pro 3.1.72, http://www.Link-Checker-Pro.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; LN; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; LTH Browser 3.02a; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Lunascape 1.3.1)" + family: "Lunascape" + major: '1' + minor: '3' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; luv u; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; lvw)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; LW0815)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Lycos-Online; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MADE BY WEBO; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MassCops Browser; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Matrix Y2K - Preview Browser; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; Alexa Toolbar)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; FDM)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; iRider 2.20.0002)" + family: "iRider" + major: '2' + minor: '20' + patch: '0002' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; MyIE2; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; MyIE2; SV1)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; MyIE2; SV1; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; (R1 1.5))" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SailBrowser 2005; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; Stardock Blog Navigator 1.0; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1; Alexa Toolbar)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; McInternetBrasil_MCAAE_3112; NusaQuiosque; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MCI Windows Corporate Image; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MCI Windows Corporate Image; QS 4.1.1.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MCI Windows Corporate Image; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MCI Windows XP Corporate Image; MCI Windows Corporate Image; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MediaPilot; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Megara Web; IE 6.05; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mercer Human Resource Consulting; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Metro C&C, Croatia)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MidBC001; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Miele & Cie. Explorer Version 6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MiniJv2 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; mip.sdu.dk)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mon_AutoConfig_v1.02_STL; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mountainside; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .Mozilla)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Menara); SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (Compatible; MSIE 6.0; Windows 2000; MCK); Mozilla/4.0 (Compatible; MSIE 6.0; Win; MCK); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; -D-H1-MS318089))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HDR.05.01.00.06; .NET CLR 1.0.3705; .NET CLR 1.1.4322); .NET CLR 1.1.4322); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible,MSIE 6.0; Windows NT; Brite Way Publishing; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0(compatible; MSIE 6; Win32; Mck))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0(compatible; MSIE 6; Win32; Mck); Mozilla/4.0 (Compatible; MSIE 6.0; Win; MCK))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (zgodny z ISO 900087635.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MPD JV v1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MRA 2.5 (build 00387))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MRA 3.0 (build 00614))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MRA 4.0 (build 00768))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MS Custom IE; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSIE6XPV1; KB824145; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; msie6xpv1; LM_POSTPLATFORM; MSIE6ENV6; MS04-004; CU_POSTPLATFORM; .NET CLR 1.0.3705; .NET CLR 1.1.4322; LM_50_POSTPLATFORM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; msie6xpv1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; msie6xpv1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmbr-br; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-sg; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmit-it; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmtc-tw; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 8.0; MSN 8.5; MSNbBBYZ; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 8.0; MSN 8.5; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-gb; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0; MSNbBBYZ; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0; MSNbDELL; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; AtHome0200; T312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; AtHome021SI; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; AtHomeEN191; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; AtHomeEN191; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; Q312461; Hotbar 4.0; SEARCHALOT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MTI; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MTI; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Multikabel)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyHealthyVet; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2 0.3)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Deepnet Explorer; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; ESB{9D28903E-AE01-4815-A52A-AE2885F86845}; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; ESB{E225A099-D057-4FEF-BAC6-3BEC123804CC}; NN5.0.2.23)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Feedreader)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Feedreader; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; FunWebProducts)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Hotbar 4.5.0.0; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; i-NavFourF; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; iOpus-I-M; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; iRider 2.10.0008)" + family: "iRider" + major: '2' + minor: '10' + patch: '0008' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; JyxoToolbar1.0; iolbar-3.0.0.XXXX; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Matrix Y2K - Preview Browser; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; AIRF; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; iOpus-I-M; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; .NET CLR 1.1.4322; FDM)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1; Deepnet Explorer; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1; .NET CLR 1.1.4322; Tablet PC 1.7; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; NetCaptor 7.0.1)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; NetCaptor 7.5.3; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.0.2914; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; (R1 1.1); FDM)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; (R1 1.1); .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; (R1 1.3))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; (R1 1.5))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; (R1 1.5); .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; CustomToolbar.com; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Mailinfo [102065]; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Maxthon; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.1.4322; FDM)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; TheFreeDictionary.com)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Nahrain)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NARA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NaturaMediterraneoEEmare; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Neostrada Plus 5.6; FIPID-{2N8gA8m2Ta32{2nYX0EkruYpg585052490; i-MailBook)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Neostrada TP 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.0.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.0.2 Final; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.0.2 Final; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.1.0 Beta 2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.2.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.2.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.2.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.0 Gold)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.0 Gold; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.0 Gold; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.2; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.2; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.3; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3621)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .BGDID000017489A1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Dave)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Googlebot; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; &id;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSN 8.0; MSN 8.5; MSNbDELL; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSN 8.0; MSN 8.5; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.0.3621; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Tablet PC 1.7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; XMPP TipicIM v.RC6 1.6.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; NetNearU)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Tablet PC 1.7; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Alexa Toolbar; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Donut RAPT #51 Sugi)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322-dtb)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Feat Ext 18)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Free Download Manager)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Lunascape 1.4.1)" + family: "Lunascape" + major: '1' + minor: '4' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmde-de; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc11; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmnl-be; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 8.0; MSN 8.5; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 8.0; MSN 8.5; MSNbVZ02; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0; MSNbBBYZ; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40426)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.31113)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.40426)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Netibar 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; SpamBlockerUtility 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Tobbes surfing board)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; XMPP TipicIM v.RC5 1.6.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40607; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40607; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40607; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Netpenny)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Netvitamine Toolbar (+http://www.netvitamine.com); i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; New Value #1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NISSC; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NISSC; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN4.2.0.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN5.0.2.23; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN5.0.3.3; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN5.0.3.3; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN5.0.600.15)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Nordstrom; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ntlworld v2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ntlworld v2.0; Hotbar 4.5.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ntlworld v2.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; nxforms/1.00; formsPlayer 1.1; formsPlayer 1.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ONET; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Ongame E-Solutions AB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ONLINE 5.5; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OnlyInternet.Net; Personal Computer Doctors)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ONS Internet Explorer 6.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OPT-OUT; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OPT-OUT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OPT-OUT; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE501-018)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE501-018; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE501-018; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-27)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-27; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-27; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-32)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Origin Energy Limited - SOE 3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OZEHAR01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OZHARLIT6.0_1_PP3; FunWebProducts; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OZHARLIT6.0_1_PP3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OZHARLIT6.0_1_PP3; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OZHARLIT6.0_HN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Paros/3.2.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PASSCALL; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PCAdvisor032002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PCPLUS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PCUser; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PeoplePal 3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Performance Technologies S.A.; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PGE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PhaseOut [www.phaseout.net]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PKBL008; fs_ie5_04_2000i)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Plus a few changes)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PNCStd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Poco 0.31; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Polkomtel S.A.; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PottsNet; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PowerBase6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Preload_01_07)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Preload_01_07; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Prepaidonline.com.au setup; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Primus-AOL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PrimusCAlanEN; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PrimusDSLEN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PrimusPCEN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PROGRATECH; MSIE6.0XP OpenBrowser CPOP5.2; DyGO.NET MailSRV; MyIE2; SV1; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Provided by Alphalink (Australia) Pty Ltd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PRU_IE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PwCIE6v01; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PwCIE6v01; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q-06062002-K2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q-06062002-K2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312460)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; 1.21.2 ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; AIRF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Amgen.v1b; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; APCMAG; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; AT&T CSM6.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; BCD2000; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; BrowserBob; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; BTopenworld; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; CDSource=ALLIED_01_01; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; CDSource=storecd_01_03; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; COM+ 1.0.2204; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Cox High Speed Internet Customer; 1.41.1 )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Cox High Speed Internet Customer; i-NavFourF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Cox High Speed Internet Customer; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Cox High Speed Internet Customer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; ESB{6C1AEBB4-8C44-41AE-866F-707D5E75B0E9}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; ESB{A44A754F-952B-4E88-802A-5725DBA66F0E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; F-6.0-20020225)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts-MyWay; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts; NetCaptor 7.5.2; WebCloner 2.3; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts; ntlworld v2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; GIL 2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hewlett-Packard; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 3.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.1.5.0; MyIE2; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.1.8.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.4.5.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.4.7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.4.7.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.5.1.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.5.1.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; IESYM6; Hotbar 4.5.0.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; IOpener Release 1.1.04)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; iOpus-I-M; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; iOpus-I-M; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MathPlayer 2.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MyIE2; Maxthon; SV1; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MyIE2; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.2914; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705; .NET CLR 1.2.2125; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; NN5.0.600.11)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; OptusNetDSL6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Paul BunyaNet; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Q-07122002-K2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; (R1 1.3); .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Roadrunner; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Roadrunner; TheFreeDictionary.com; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; sbcydsl 3.12; YComp 5.0.0.0; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SIK30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; 18ko/; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; ATB; Visited by ATB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; GIL 2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; IBP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; T312461; SV1; EnergyPlugIn; dial; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; TeomaBar 2.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; TeomaBar 2.01; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; TeomaBar 2.01; SV1; MSN 6.1; MSNbMSFT; MSNmja-jp; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; tiscali; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; TUCOWS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; TVA Build 2001-10-11)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.2.5; Hotbar 4.2.8.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.2.6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YPC 3.0.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YPC 3.0.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312462)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312463)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312464)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312465)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312466)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312467)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312468)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312469)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321017)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321017; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321120; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321120; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321120; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321150; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q822925; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QinetiQ IE6 V02; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QS 4.1.1.2; DVD Owner; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QS 4.1.2.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QS 4.1.2.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QS 4.1.2.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Queensland Government; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QUT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QUT Printing Services; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Qwest - 11122003-a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Qwest - 11122003-a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Qwest - 12302003-sms)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Qwest - 12302003-sms; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QXW0330d; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QXW0339d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QXW0340e; www.ASPSimply.com; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.1); FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.1); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.1); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3)),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; [R1 1.3]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; RD&E v.6.0 r.6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; RD&E v.6.0 r.6; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Really Firefox-It works fine asshole)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Renault)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Renault; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; RI-ADMIN12112003)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; FunWebProducts; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; Hotbar 4.4.2.0; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; TheFreeDictionary.com; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; YPC 3.1.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; YPC 3.1.0; yplus 4.5.03b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; RSD66)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; rtc user)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; rtc user; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; RWE Dea AG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)-s" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SALT 1.0.3404.1 1007 Developer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SALT 1.0.4223.1 0111 Developer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SALT 1.0.4223.1 0111 Developer; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SALT 1.0.4613.0 0111 Developer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SALT 1.0.5507.1 0111 Developer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SAVEWEALTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; ESB{E49F02C9-B446-4F5C-9EB8-5A2DF808DA80}; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; FunWebProducts; YPC 3.0.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; SV1; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; SV1; YPC 3.0.3; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; yie6_SBCDSL; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YPC 3.0.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YPC 3.0.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SBS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SBS; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SC/5.10/1.14/Telenor)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SC/5.10/1.14/Telenor; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SC/5.60/1.01/FS-Internett; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; School of Business and Computing; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SCL Build)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ScreenSurfer.de; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SEARCHALOT.COM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SEARCHALOT.COM; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SearchFox Toolbar 2.0b1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sfgdata=5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SFIE60122601; SFIEAUTH1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SFIEAUTH1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SGC; SGC STUDENTS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sgrunt|V107|634|S-1869674593|dialno; alice01; snprtz|dialno; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sgrunt|V109|1684|S-129601565|dial; snprtz|S03037726560360)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sgrunt|V109|622|S1290160941|dialno; snprtz|dialno)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sgrunt|V109|69|S-327757572|dialno)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Shazam; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Siemens A/S; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; FunWebProducts; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; FunWebProducts; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SINGNET)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SINGNET/HTMLAB; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SiteCoach 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SKY11a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SKY13; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SlimBrowser [flashpeak.com])" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Smart Explorer 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Smart Explorer 6.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Smart Explorer 6.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Smart Explorer v6.0 ( Evaluation Period ))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Smart Explorer v6.0 ( Evaluation Period ); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snft internet; SV1; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snopud.com client; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Snowdrop Systems; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snprtz|dialno; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snprtz|S03037726560360)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snprtz|T03022004250337; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snprtz|T04125278003990)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SOK)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SON-1102CD; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SON-1102CD; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sp1, AHS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SP/6.35/1.01/ONLINE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SPARTA AREA SCHOOLS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SPServe)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; **SPS**; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SS.CC. Palma)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StarBand Version 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StarBand Version 4.0.0.2; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StarBand Version 4.0.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StarBand Version 4.0.0.2; SV1; .NET CLR 1.0.3705; Media Center PC 2.8; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {Starpower})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; STB; 560x384; MSNTV 4.1; THMDR)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; STIE60-021004; STIE60-020212; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; STI; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; STI; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stokeybot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Stonehenge School)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StopTrackingMe; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Stratford ISD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.733; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.735; MyIE2; SV1; Maxthon; JyxoToolbar1.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.735; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.736; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.744)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.755)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.755; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.758; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.758; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.760)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.760; iRider 2.21.1108; .NET CLR 1.1.4322)" + family: "iRider" + major: '2' + minor: '21' + patch: '1108' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.760; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.760; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.760; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.763)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.763; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.818; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.820; SV1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.901; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.906; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.910; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.910; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.910; SV1; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.917; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.917; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.917; SV1; Hotbar 4.5.1.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.919; Maxthon; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.919; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.923; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.923; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.924; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.924; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.925; .NET CLR 1.0.3705; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.926; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.926; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; subagente; Agente; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sunrise; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by blueyonder)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by blueyonder; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by blueyonder; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by blueyonder; SV1; Hotbar 4.5.1.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by blueyonder; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by Tesco.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Surf Mechanic; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; 1.41.1 ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; 1.56.1 ; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; 9LA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; ACTC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AIRF; NetCaptor 7.2.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AIRF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; jd; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; ALL YOUR BASE ARE BELONG TO US; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Antenna Preview Window)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Antenna Preview Window; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AOL7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; APCMAG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Arcor 5.002; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Arcor 5.002; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Arcor 5.003)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AskBar 3.00; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AT&T CSM6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AT&T CSM7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AT&T CSM8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AUTOSIGN W2000 WNT VER03)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AVPersonalSerial 2b206c294a291e6470432759423669f000255953; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BBIP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BCD2000; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Berg Network Client; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BMD Melbourne; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Boeing Kit; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; brip1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BTHS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BT Openworld BB; YPC 3.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BT Openworld Broadband; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BT Openworld Broadband; YPC 3.2.0; yplus 4.3.02d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BTY; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Burnie High Student)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Canning College)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CaseDOSA/Operator; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CDSource=BP1b.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CDSource=v11c.01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CDSource=v9e.04; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CIM Gruppen; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Citrix)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Compatible; Version; ISP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Cox High Speed Internet Customer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Cox High Speed Internet Customer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Creative; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CSIE60SP02; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CursorZone 1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CursorZone Grip Toolbar 2.08; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; custom; custom; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; custom; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer 1.3.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DHSI60SP1001; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DI60SP1001)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DigExt; FunWebProducts; Media Center PC 3.0; .NET CLR 1.0.3705; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; D-M1-200309AC;D-M1-MSSP1; D-M1-200309AC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DOJ3jx7bf; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Domain user; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Donkey; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DownloadSpeed; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DVD Owner; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Editor 3.0 - http://www.e-ditor.com; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; ESB{77898B69-9C1F-433D-B8EA-FD6FA2B8A2CC}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; ESB{C6B1C008-FCCB-4A07-BF79-6BEED181D1F0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; E-train)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; evUI; Agency Manager Management Console; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FeedEater; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Feedreader; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Feedreader; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Feedreader; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Feedreader; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Feedreader; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; formsPlayer 1.3; nxforms/1.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FREE; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FTDv3 Browser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FTDv3 Browser; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; 1.56.1 ; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; 1.56.1 ; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Alawar 2.08; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Hotbar4.5.3.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Hotbar4.5.3.0; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; i-NavFourF; onlineTV; www.cdesign.de; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyWay; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmnl-nl; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; (R1 1.1); (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; SpamBlockerUtility 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GambleEnt; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; gameland)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GIS IE6.0 Build 20031111; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GMX AG by USt; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; gogo)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Golfing Paradise; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Tablet PC 1.7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Grip Toolbar 2.07a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Grip Toolbar 2.08; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Headline-Reader; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; HEL INTERNET EXPLORER)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.2.14.0; .NET CLR 1.0.3705; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.4.6.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.5.1.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.5.1.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar4.5.3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar4.5.3.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.6.1; MSN 6.1; MSNbMSFT; MSNmnl-nl; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar Unknown; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; HTMLAB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://www.aztrx.com/ )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://www.tropicdesigns.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://www.tropicdesigns.net; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; IBP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; IBP; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; IBP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; IBP; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Imperial College; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; Wanadoo 6.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iP-CMPQ-2003; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iP-CMPQ-HDD; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; IWSS:wxp4432/00114366da97; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; JNet; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; JUNO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; KATIESOFT 6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; KKman3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; LetNet Connect, [www.letu.edu]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; lWh.lgS.rfU.lxd; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Manor Trust::)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MathPlayer 2.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MathPlayer 2.0; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 2.0.41202)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MathPlayer 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; Alexa Toolbar)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; FREE)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; FREE; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; NetCaptor 7.5.4)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322; FDM)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322; FDM; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; (R1 1.5); .NET CLR 2.0.40903)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MaxXium; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Media Center PC 3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Media Center PC 3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Media Center PC 3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MediaPilot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT; Campus Bundaberg;))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.0 (build 00768); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.0 (build 00768); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSCS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbDELL; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmfr-fr; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmnl-nl; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 9.0;MSN 9.1; MSNbQ002; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MTI; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MTK; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; iebar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; (R1 1.3))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; TaxWise19.00[0016]; TaxWise19.01[0003]; TaxWise19.02[0005]; TaxWise19.03[0001]; TaxWise19.04[0001]; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Neostrada Plus 5.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Neostrada TP 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.2.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.0 Gold; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.2; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.2; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.3; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.3; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.4; Media Center PC 3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 2.8; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 2.8; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 3.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; MSN 6.1; MSNbMSFT; MSNmit-it; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1; Googlebot/2.1)" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1; .NET CLR 2.0.40209)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Tablet PC 1.7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; XMPP TipicIM v.RC6 1.6.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 2.0.40607; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Tablet PC 1.7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Tablet PC 1.7; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Tablet PC 1.7; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; 45c42354c4e5r4cw!(s)4sd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Alexa Toolbar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Alexa Toolbar; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322) Babya Discoverer 8.0:" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; FDM; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Hotbar 4.6.1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Hotbar 4.6.1; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Lunascape 1.4.0beta3)" + family: "Lunascape" + major: '1' + minor: '4' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Lunascape 1.4.1)" + family: "Lunascape" + major: '1' + minor: '4' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Lunascape 1.4.1),gzip(gfe) (via translate.google.com)" + family: "Lunascape" + major: '1' + minor: '4' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Lunascape 2.0.1)" + family: "Lunascape" + major: '2' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmde-at; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc0z; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc11; MSNc11)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc11; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc21; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmit-it; MSNc0z; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbBC01; MSNmen-ca; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbBC01; MSNmfr-ca; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-gb; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbQ002; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSNc11; MSN 6.1; MSNbMSFT; MSNmen-us)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.2914; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.2914; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Version; Platform; Compatible)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40209)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40903; Avalon 6.0.4030)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.41115)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.41202)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50110)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50110; Avalon 6.0.4030)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50215)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; NOKTURNAL KICKS ASS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Secure IE 3.3.1263)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Tablet PC 1.7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607; .NET CLR 2.0.40426; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40903; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.41118; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50126)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Net M@nager V4.00 - www.vinn.com.au)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetPanel:763771; npUID:763771; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NN4.2.0.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; N_O_K_I_A)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) NS8/0.9.6" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; nxforms/1.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OfficeWorld.com/1.082)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusIE55-31; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6; MathPlayer 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Overture; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Poco 0.31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Poco 0.31; TencentTraveler ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; PrimusDSLEN; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Prisoner; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; provided by blueyonder; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Quik Internet (0102098b))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); .NET CLR 1.0.3705; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); onlineTV; www.cdesign.de)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); snprtz|T04077983781234)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; RCBIE6XPMAN; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SALT 1.0.3404.1 1007 Developer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SALT 1.0.5507.1 0111 Developer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SALT 1.0.5507.1 0111 Developer; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Sgrunt|V108|654|S-2135541317|dial; snprtz|T03087750360356; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Sgrunt|V109|34|S-1398421108|dialno; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Sgrunt|V109|547|S1107901103|dial; XBE|29|S04039483631143; snprtz|S04048557771347)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Sgrunt|V109|598|S76509116|dialno)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SIK30; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SIK30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SLPS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SmartShop)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SON-1102CD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SON-1102CD; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SPARTA AREA SCHOOLS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; sumit)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Suncorp Metway Ltd; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Supplied by blueyonder)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Supplied by blueyonder; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Supplied by Tesco.net; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; surfEU FI V3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Tablet PC 1.7; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Tablet PC 1.7; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TBP_6.1_AC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TencentTraveler )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TeomaBar 2.01; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TeomaBar 2.01; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TheFreeDictionary.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TheFreeDictionary.com; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TNET5.0NL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; urSQL; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; User Agent; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; UserAgent; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Virgin 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; VND Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; VNIE5 RefIE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; VNIE5 RefIE5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; VNIE60; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; VNIE60; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wanadoo 5.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wanadoo 6.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wassup; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; WebSpeedReader 8.6.96; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; WHCC/0.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; WHCC/0.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; WHCC/0.6; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; WI4C 3.5.3.001; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; www.ASPSimply.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; www.aztrx.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; www.k2pdf.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wysigot 5.51)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; XMPP TipicIM v.RC6 1.6.8; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; XN2K3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; yie6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; yie6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; yie6_SBC; YPC 3.0.3; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.2; .NET CLR 1.1.4322; yplus 4.4.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.3; .NET CLR 1.1.4322; yplus 4.0.00d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.3; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.1.0; bgft; Media Center PC 3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.1.0; Media Center PC 3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.1.0; yplus 4.5.03b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SWSIT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SWSIT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sykes Enterprises Inc. B.V.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SYMPA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SYMPA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SYMPA; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SYMPA; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; Artabus)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; DI IE 5.5 SP2 Standard; GESM IE 5.5 SP2 Standard; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; PGE; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; Q312461; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TARGET HQ; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TaxWise19.00[0016]; TaxWise19.05[0002]; TaxWise19.07[0006]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_6.1_AC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_6.1_AC; NetCaptor 7.5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_6.1_AC; (R1 1.3); Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBPH_601)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TDSNET8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; telus.net_v450HS; SV1; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; telus.net_v5.0.1; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TencentTraveler )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TencentTraveler ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TeomaBar 2.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TeomaBar 2.01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TeomaBar 2.01; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Testing.net; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Texas Instruments)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Texas Instruments, Inc; [R1 1.3]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; The Department of Treasury - Bureau Of The Public Debt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TheFreeDictionary.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TheFreeDictionary.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TheFreeDictionary.com; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; The Free Lance-Star Publishing Company)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Thiess Pty Ltd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; tip; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TiscaliFreeNet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Tiscali; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TMS Inst 5.5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TNT Australia Pty Ltd; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Total Internet; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TR.NET Dialup Ver.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TRPIT; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TRPIT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TS User; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TUCOWS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TVA Build 2002-05-16)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TVA Build 2002-05-16; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; U)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; UBIS-RESNET 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; UKPORTAL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; UrIE 4.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; urSQL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; %username%; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; USERNAME_PASSWORD_IS_ENABLED; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; UUNET)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; V1.0Tomorrow1000; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; v11b.01; FunWebProducts; SV1; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; V6.00-003)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; v6.1b; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; V6; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Videotron)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Videotron; SV1; CustomExchangeBrowser; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VIRTUALIT.BIZ; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Virtual IT - http://www.virtualit.biz)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE4 3.1.814; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE5 RefIE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE5 RefIE5; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE5 RefIE5; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE5 RefIE5; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE60)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE60; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE60; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE60; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE60; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Voicecrying.com; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Voyager II; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; vtown v1.0; FunWebProducts; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo042NLPP01HCFFFFFFEC; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo042NLPP01HCFFFFFFFA; AtHome033)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5; SV1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5; Wanadoo 6.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5; Wanadoo 6.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5; Wanadoo 6.2; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.6; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.6; Wanadoo 6.1; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.1; Wanadoo 6.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.2; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo Câble 5.6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Was guckst du?; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WCCTA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; weasel & chicken; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WebSpeedReader 8.7.4; Hotbar 4.5.1.0; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) WebWasherEE/3.4.1 3.4.1" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Westerville Public Library; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WestNet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Weybridge; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHCC/0.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHCC/0.6; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHCC/0.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHCC/0.6; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHCC/0.6; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHO Synergy II; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wile E. Coyote Build - ACME)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows XP SP2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows XP SP2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WinXP-SOE v3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WODC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .WONKZ)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wooohooooooooooooooooooooooooooo!; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; World Interactive Software)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {World Online})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WRV)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; W&S; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WWIEPlugin; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.amorosi4u.de.vu)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.Bertram-Engel.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.BERTRAM-ENGEL.com Webmaster; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.k2pdf.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.k2pdf.com; Compatible; Version; Platform)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.k2pdf.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.k2pdf.com; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.k2pdf.com; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.oxy-com.com; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.spambully.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.spambully.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.wbglinks.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wysigot 5.22; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wysigot 5.4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; X Channel Browser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; XTM02b Beta 1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; XTM02b Beta 1; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; FunWebProducts; Hotbar 4.5.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; FunWebProducts-MyWay; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; Hotbar 4.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; Rogers Hi-Speed Internet; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; sbcydsl 3.11; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; sbcydsl 3.12; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; SEARCHALOT; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.4; AskBar 2.11)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.4; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.5; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; ntlworld v2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.8.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.8.6; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.8.6; SV1; yplus 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6)Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBCDSL; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBCDSL; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBCDSL; sbcydsl 3.12; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBC; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; sbcydsl 3.12; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBC; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; YPC 3.0.3; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; YPC 3.0.3; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; BT Openworld BB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; BTopenworld; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; FunWebProducts; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; SV1; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; SV1; yplus 4.0.00d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; FunWebProducts; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; FunWebProducts; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; Hotbar 4.4.2.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; NetCaptor 7.5.0 Gold)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; (R1 1.3); (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; (R1 1.5; yplus 4.1.00b))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; yie6_SBC; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; BT Openworld BB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; BT Openworld BB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; BT Openworld BB; .NET CLR 1.1.4322; yplus 4.3.02d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; BT Openworld BB; SV1; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; BT Openworld BB; SV1; yplus 4.3.02d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.0.3705; yplus 4.4.02d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.1.4322; .NET CLR 1.0.3705; yplus 4.4.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.1.4322; yplus 4.3.01b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.1.4322; yplus 4.3.02b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; SV1; ESB{4146F2DC-3320-4F28-8906-D3591D69426E}; TheFreeDictionary.com; yie6-uk; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; SV1; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; SV1; yplus 4.3.02b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; yplus 4.3.02b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; yplus 4.3.02d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; yplus 4.4.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; FunWebProducts; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; SV1; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; SV1; .NET CLR 1.1.4322; Hotbar 4.6.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; SV1; .NET CLR 1.1.4322; yplus 4.0.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; SV1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.1.0; SV1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.1.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.1.0; SV1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.2.0; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Z-HARPE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Zurich North America; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {2C2E9759-7422-4D75-89A2-9C0419FE3957}; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {2D24C5F8-6342-4582-8057-099D1FBBF5EC}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {4372BAAC-73EB-4BF5-9A5F-E4F106925C4E}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {61F2E4DF-60B7-4C8A-8BD9-98853FF61315}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {85167A96-330B-4FA4-B250-90A9AA0F0FCF}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {8D08774B-017A-4392-97D1-F9D354660A55}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; ATLAS.SK_01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Data Center; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2;;) [de]" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; demne is my dog)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; digit_may2002; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; EFW TSC2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Feedreader; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; FunWebProducts-MyWay; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Glazenzaal; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; GruppoMPS; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; H; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Infowalker v1.01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; iTreeSurf 3.6.1 (Build 056); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; LCC Internal User - 010; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; LCC Internal User - 014; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; (R1 1.5); .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; SV1; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Moneysupermarket.com Financial Group; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; iTreeSurf 3.6.1 (Build 056); .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; NetCaptor 7.5.0 Gold; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; NetCaptor 7.5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; NetCaptor 7.5.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40420)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.40419)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.41115)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 2.0.31113;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Poco 0.31; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Q321120; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; (R1 1.5); .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SALT 1.0.0.0 1007 Developer; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; stumbleupon.com 1.923; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; TencentTraveler ; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Weybridge; .NET CLR 1.1.4322; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64; AMD64)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64; x64; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64; x64; SV1; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; WOW64; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; WOW64; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; www.ASPSimply.com; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 6.0; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT; MS Search 4.0 Robot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible;MSIE 6.0; Windows XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows XP Professional Bot v.5.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows 2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible;MSIE 6.0; Windows 3.11)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible;MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 8.3; )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible;MSIE 6.0;Windows XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 [de] (compatible; MSIE 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 [en] (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/6.0 (compatible; MSIE 6.0; Windows 3.11 For workgroups; {6BD3E7C1-0732-43E8-8828-291A709CC070})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MSIE 6.0 (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE 6.0 (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE/6.0 (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE 6.0 (compatible; MSIE 6.0; Windows NT 5.1)/4.78 (TuringOS; Turing Machine; 0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE 6.0)\" (MSIE 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE 6.0 (+MSIE 6.0; Windows NT 5.0; Q312461;; MSIE; Windows)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE 6.0 (Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE/6.0 ( Windows NT 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MSIE/6.0 (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MSIE 6.0 (Win XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.01; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.02; Windows 98)" + family: "IE" + major: '6' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.3 (compatible; MSIE 6.2; Windows NT 6.0)" + family: "IE" + major: '6' + minor: '2' + patch: + - user_agent_string: "Mozilla/6.1 (compatible;MSIE 6.5; Windows 98)" + family: "IE" + major: '6' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 7.66; Windows NT 5.1; SV1)" + family: "IE" + major: '7' + minor: '66' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 7.66; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '7' + minor: '66' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 8.0; Windows 94)(2000/08/12-2000/08/24)" + family: "IE" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 7.0a1; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MS IdentiServ 1.4.12)" + family: "IE" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSXPLAYer2.014)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; MuscatFerret/1.6.3; claude@euroferret.com) via proxy gateway CERN-HTTPD/3.0 libwww/2.17" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MVAClient" + family: "Other" + major: + minor: + patch: + - user_agent_string: "My Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; NCSA_Mosaic; windows; SV1; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.6 (X11;IRIX 4.0.5F IP12)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; Netbox/3.5 R92.5; Linux 2.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; NetBox/3.5 R92.3; Linux 2.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; Netbox/3.5 R93rc3; Linux 2.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; Netgem/3.6.7; netbox; Linux 2.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ZoneSurf/2.4 (BeOS; U; BeOS 5.0 BePC; en-US; 0.8)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; NetPositive/2.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; NetPositive/2.2.1; BeOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; NetPositive/2.2.2; BeOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; NetPositive/2.2.3; FreeBSD 5.2.1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "netscape (compatible; netscape; linux; SV1; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Netscape 7.0; Windows 98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Netscape 7.0; Windows NT 4.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible;Netscape 7.1; Windows 98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Netscape 7.3R; Windows 92)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 Netscape 7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (Netscape 4.79; Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows NT 5.0) Netscape 7.1" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Netscape 4.08; Windows 98; DigExt)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible;Netscape 4.76 Mozilla 1.4;Linux 2.6.7)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Netscape 7.0; Windows 98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Netscape Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows XP; en-US; rv:1.7.5) Netscape 7.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-CA; rv:0.9.4) Gecko/20011128 Netscape 7.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113 Netscape 7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Netscape Navigator 4.x/4.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020921 BigBrother/Netscape6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.1 [en] (Windows NT 5.1; U)Netscape" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Navigator/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape 1.22 (Win16; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape 2.1 (compatible; MSIE 2.0B1; Windows for Workgroup 3.11; i386; en-US)" + family: "IE" + major: '2' + minor: '0' + patch: + - user_agent_string: "Netscape 4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en]C-WNS2.5 (Wim95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (Win2000; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (X11; I; HP-UX B.10.20 9000/712)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (X11; I; SunOS 5.5.1 sun4m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 (Linux i686; 1.7.3; Linux i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.05 [en] (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.05 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.05 [fr] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.05 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 [en] (Direct Hit Grabber)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 [en] (X11; U; Linux 2.0.27 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 (Macintosh; I; PPC, Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.07C-SGI [en] (X11; I; IRIX 6.5 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.07 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.07 [en] (X11; I; Linux 2.0.36 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.07 (X11; I; Nav; Linux 5.1.33 i586; )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (Win16; I ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (Win16; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en](Win95; U; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (Win98; I ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (Win98; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (Windows 3.11; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (WinNT; I ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (WinNT; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (X11; U; Linux 2.4.9-34 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [fr] (Win95; I ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 (Macintosh; U; PPC, Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 (PDA; PalmOS/sony/model atom/Revision:2.0.22 (en)) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PDA; PalmOS/sony/model atom/Revision:2.0.26 (de)) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PDA; PalmOS/sony/model luke/Revision:2.0.22 (en)) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PDA; PalmOS/sony/model luke/Revision:2.0.26 (de)) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PDA; PalmOS/sony/model prmr/Revision:2.0.22 (en)) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PDA; Windows CE/1.0.0) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PPC; Windows CE/1.0.0) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (SmartPhone; Symbian OS-Series60/1.03) NetFront/3.2" + family: "NetFront" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/4.1 (BEOS; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.1 [ja] (X11; I; Linux 2.2.13-33cmc1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.41 (BEOS; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [de] (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en]C-AtHome0405 (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en]C-CCK-MCD snapN45b1 (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en]C-CCK-MCD (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en] (X11; I; Alpha 06; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en] (X11; I; IRIX64 6.5 IP30) Mozilla/4.08 [en] (Win95; I ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [fr] (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 RPT-HTTPClient/0.3-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 (Windows; U; Windows NT 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape/4.5 (WindowsNT;8-bit)" + family: "Netscape" + major: '4' + minor: '5' + patch: + - user_agent_string: "Netscape Navigator 4.5 (Windows; U; Windows NT 5.1; sl-SI; rv:1.4) Netscape/4.5" + family: "Netscape" + major: '4' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.51C-ASML_1N06S [en] (X11; I; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [de]C-CCK-MCD DT (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [de]C-CCK-MCD FS SBS (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [de]C-CCK-MCD QXW03200 (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [de]C-CCK-MCD QXW03200 (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [de] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [en]C-CCK-MCD (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.6 [de]C-freenet 4.0 (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.6 [de] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.6 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [de] (OS/2; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en]C-CCK-MCD (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en]C-CCK-MCD (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (OS/2; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (X11; I; Linux 2.2.13-33cmc1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (X11; I; Linux 2.4.25 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (X11; U; ) - BrowseX (2.0.0 Windows)" + family: "BrowseX" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.61 [en] (X11; U; FreeBSD 4.9-RC i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [ja] (X11; I; Linux 2.2.13-33cmc1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 (X11; )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7C-CCK-MCD {C-UDP; EBM-APPLE} (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7C-CCK-MCD [en] (X11; I; SunOS 5.6 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de]C-CCK-MCD 1&1 PureTec Edition 02/2000 (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de]C-CCK-MCD QXW0322a (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de]C-freenet 4.0 (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de]C-SYMPA (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de] (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de] (X11; Linux)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en]C-CCK-MCD EBM-Compaq1 (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en]C-CCK-MCD NSCPCD47 (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en]C-SYMPA (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en-gb] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en, US, en_US] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; AIX 4.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; HP-UX B.10.20 9000/782)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; Linux 2.6.4 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; OSF1 V4.0 alpha)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; SunOS 5.8 i86pc)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [fr]C-CCK-MCD C_ASPI_1_0 (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [fr] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [fr] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [ja] (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [ja] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [ja] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (Macintosh; ppc)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (X11; Linux)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7x [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7x [en] (Win9x)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.71 [en]C-NECCK (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.71 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.71 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (Win95; I) WebWasher 3.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (X11; I; Linux 2.2.14 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73C-CCK-MCD VerizonDSL (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [de]C-CCK-MCD DT (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [de]C-CCK-MCD DT (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [de]C-CCK-MCD DT (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [de] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en]C-SYMPA (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en] (Windows NT 5.0; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en] (X11; U; Linux 2.2.19 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.74 [en]C-DIAL (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.74 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.74 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75C-CCK-MCD {C-UDP; EBM-APPLE} (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75C-CCK-MCD {C-UDP; EBM-APPLE} (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75C-CERN UNIX pcjinr02 45 [en] (X11; U; Linux 2.2.19-6.2.1.1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 compatible - Mozilla/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [de]C-CCK-MCD DT (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [de]C-CCK-MCD QXW0325g (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [de] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en]C-CCK-MCD {C-UDP; VUT} (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en]C-CCK-MCD {Nokia} (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en]C-CCK-MCD (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (X11; U; Linux 2.2.16-22 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (X11; U; SunOS 5.6 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (X11; U; SunOS 5.7 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 (000000000; 0; 000)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76C-SGI [en] (X11; I; IRIX 6.5 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en]C-bls40 (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en]C-CCK-MCD cf476 (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en]C-CCK-MCD (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (PalmOS; U; WebPro/3.0; Palm-Arzl)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; FreeBSD 5.2-RC i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; HP-UX B.11.00 9000/785)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; Linux 2.2.18 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; Linux 2.4.16 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; Linux 2.4.2-2 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; Linux 2.4.2-2 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; OSF1 V5.1 alpha)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; SunOS 5.7 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; SunOS 5.8 i86pc)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; SunOS 5.8 sun4m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76iC-CCK-MCD [en_US] (X11; U; AIX 4.3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 (Macintosh; I; PPC; Incompatible my ass! What if I don't want your jerky, elitist, ugly-assed css crap? Screw you!)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 (X11; U; Linux 2.6.3 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 (BeOS; U; BeOS BePC; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77C-CCK-MCD {C-UDP; EBM-APPLE} (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [de] (X11; U; Linux 2.2.19-SMP i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en]C-SYMPAL (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en]C-SYMPAL (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; AIX 4.3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; Linux 2.2.19-6.2.1 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; Linux 2.4.2-2 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; Linux 2.4.24 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; Linux 2.4.27-c800-1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; Linux 2.4.9-34 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; SunOS 5.7 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78C-br_XT_4_78 [en] (X11; U; SunOS 5.8 i86pc; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78C-CCK-MCD [en] (X11; U; HP-UX B.10.26 9000/785)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78C-CCK-MCD vg_472 [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78C-ja [ja/Vine] (X11; U; Linux 2.4.22-0vl2.11 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [de]C-CCK-MCD DT (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [de] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [de] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [de] (X11; U; Linux 2.4.7-10 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (Win98; I) IBrowse/2.3 (MorphOS 1.4)" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "Mozilla/4.78 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; AIX 4.3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; Linux 2.2.13 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; Linux 2.4.16-4GB i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; Linux 2.4.7-10 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; Linux 2.4.8-26mdk i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; Linux 2.4.9-34 i686; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; SunOS 5.9 i86pc)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; SunOS 5.9 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [ja] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [ja] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [uk] (WinME; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-Boeing UNIX Kit [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-CCK-MCD [en] (X11; U; Linux 2.4.28-1-p4smp i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-CCK-MCD [en] (X11; U; SunOS 5.9 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-SGI [en] (X11; I; IRIX64 6.5 IP30)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-SGI [en] (X11; I; IRIX64 6.5 IP35)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-SGI [en] (X11; I; IRIX 6.5 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [de] (X11; U; Linux 2.2.20 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en]C-CCK-MCD {UMUC/CCKUS} (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; HP-UX B.11.00 9000/785)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; Linux 2.2.12 i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; Linux 2.4.18-3 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; Linux 2.4.2 i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; SunOS 5.8 sun4m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; SunOS 5.8 sun4u; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; SunOS 5.9 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape 4.79" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 (AmigaOS 3.5; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8C-SGI [en] (X11; U; IRIX64 6.5 IP30)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8C-SGI [en] (X11; U; IRIX 6.5-ALPHA-1278921420 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8C-SGI [en] (X11; U; IRIX 6.5 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [de] (X11; U; Linux 2.6.4-52-default i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en]C-CCK-MCD EBM-Compaq (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en]C-CCK-MCD (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Linux; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (MSIE; Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Solaris)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Win3.11; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Windows NT 5.1; U) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (wouw)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.2.16-22 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.18-3smp i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.20-4GB i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.26 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.27-ow1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.2 i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.2 i386; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.2 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [fr] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [us] (X11; U; Linux 2.4.26 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 (Win)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.25 Netscape/5.0 (X11; U; IRIX 6.3 IP32)" + family: "Netscape" + major: '5' + minor: '0' + patch: + - user_agent_string: "Netscape/5.001 (windows; U; NT4.0; en-us) Gecko/25250101" + family: "Netscape" + major: '5' + minor: '001' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; m18) Gecko/20001108 Netscape6/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; m18) Gecko/20001108 Netscape6/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en; rv:1.0) Netscape/6.0" + family: "Netscape" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; m18) Gecko/20010131 Netscape6/6.01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.4.2-2 i586; en-US; m18) Gecko/20010131 Netscape6/6.01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Linux 2.6.5) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1\"" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:7.01) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.6) Gecko/20040206 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US) Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.6) Gecko/20020604 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:0.9.2) Gecko/20011002 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.5 (Windows; U; Windows NT 5.1; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape 6.1 (X11; I; Linux 2.4.18 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Netscape6/6.2.1; Macintosh; en-US)" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 Galeon/1.3.17 (X11; Linux i686; U;) Gecko/0-pie Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.4.1) Gecko/20020318 Netscape6/6.2.2" + family: "Netscape" + major: '6' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.4) Gecko/20011022 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.4) Gecko/20011130 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; fr-FR; rv:0.9.4) Gecko/20011130 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-CA; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-CA; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 (CK-SillyDog)" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4) Gecko/20011022 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; mag1001; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 (ax)" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; pl-PL; rv:1.7.6) Gecko/20050309 Netscape/6.2" + family: "Netscape" + major: '6' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2" + family: "Netscape" + major: '6' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT5.1; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2" + family: "Netscape" + major: '6' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20011022 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20011126 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv 1.3) Gecko/20030313 Netscape6/6.2.3_STRS" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20011022 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape 6.2 (Macintosh; N; PPC; ja)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040803 Netscape6/6.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows; NT 5.0) Netscape/7" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Netscape 7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Netscape/7.0;)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-CA; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-CMIL)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (nscd2)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; mag0802; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.1) Gecko/20040823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-Friars!)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-LucentTPES)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-NGA)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-N_O_K_I_A)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc2) Gecko/20020512 Netscape/7.0b1" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc2) Gecko/20020618 Netscape/7.0b1" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0 (BDP)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0 (BDP),gzip(gfe) (via translate.google.com)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-10527)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-4arcade)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-AAPT)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-FRS)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-WICGR/MIT)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (OEM-HPQ-PRS1C03)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.0 (NSEUPD V44 14.11.2003)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; AIX 000F384A4C00; en-US; rv:1.0.1) Gecko/20030213 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.4.2-2 i586; en-US; m18) Gecko/20010131 Netscape7/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux-2.6.4-4GB i686; en-US; m18;) Gecko/20030624 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux; en-US; rv:1.0.1) Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0rc2) Gecko/20020513 Netscape/7.0b1" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4m; en-US; rv:1.0.1) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020719 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020921 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4a) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; fr-FR; rv:1.0.1) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; ja-JP; rv:1.0.1) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4us; en-US; rv:1.0.1) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/7.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "\"Netscape 7.0\"" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Netscape/7.0 (BeOS 5; x86; NetServer; en-US) Gecko/20040604" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Netscape/7.0 [en] (Windows NT 5.1; U)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; ja-JP; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.01 (CK-FEL-IcD)" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 (CK-Disanet)" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 (CK-N_O_K_I_A)" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.01 (ax) (CK-SillyDog)" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; ja-JP; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-CA; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (ax)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (CK-SillyDog)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (CK-DNJ702R1)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040617 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pt-BR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (ax)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (CK-MIT)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (VAUSSU03)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02 (CK-Ifremer)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US) Netscape7/7.02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Netscape 7.02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows NT 5.0) Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; X11; U; SunOS 5.8 sun4u) Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Netscape7.1; Windows NT 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; rv:1.4; U) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:0.9.2) Gecko/20010726 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; Localization; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.2) Gecko/20010726 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; CDonDemand-Dom)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; PROMO)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) WebWasher 3.3" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; CDonDemand-Dom)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (CK-UKL)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030603 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; CDonDemand-Dom)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) (CK-SillyDog)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; PROMO)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 StumbleUpon/1.906 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040210 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.1) Gecko/20040707 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.2) Gecko/20010726 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; BDP)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; CDonDemand-Dom)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) (CK-SillyDog)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; PROMO)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Mozilla; Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041204 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Mozilla/5.0 (Windows; U; Win98; en-US; Localization; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)/0.10 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 7.0; en-US; rv:1.7.3) Gecko/20040910 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US) Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (CK-DNJ71R1)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.8a2) Gecko/20040527 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT; en-US; Localization; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; Windows NT 5.1; .NET CLR) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686) Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040418 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux-2.6.4-4GB i686; en-US; m18;) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (BDP)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031007 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040324 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040913 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/7.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape/7.1 (compatible; Linux; X11; de_DE; U) [Firefox 0.8]" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Netscape/7.1 [de] (Windows NT 5.1; U)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows NT 5.0; PPC Mac OS X; en-us) Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050204 Netscape/7.2 (PowerBook)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050208 Netscape/7.2 (PowerBook)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007 Netscape/7.2e6/6.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (OpenBSD; en-US) Gecko/20030624 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; en-GB; rv:1.7.2) Gecko/20040804 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; Localization; rv:1.4) Gecko/20030624 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; nl-NL; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape7/7.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax) Mnenhy/0.6.0.104" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; sk-SK; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax [RLP])" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (Donzilla/0.2)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (Donzilla/0.6a)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (Donzilla/0.6a2)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 StumbleUpon/1.995 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040625 Netscape/7.2 (as)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040625 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.5) Gecko/20031007 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6 (Compatible with Netscape/7.2)) Gecko/20041027 Debian/1.6-5.1.0.45.lindows0.69" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040805 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050306 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Netscape 7.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Netscape 7.2 (X11; I; Linux 2.4.18 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20050208 Netscape/7.20" + family: "Netscape" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Netscape/7.3 (ax)" + family: "Netscape" + major: '7' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Netscape/8.0" + family: "Netscape" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; Localization; rv1.4) Gecko20030624 Netscape7.1 (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; NetVisualize b202)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; NEWT ActiveX; Win32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Nintendo64/1.0 (SuperMarioOS with Cray-II Y-MP Emulation)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Nintendo64/1.7 (SuperMarioOS with Sun 15K Y-MP Emulation)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NoctBrowser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Nokia 6600" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3100/1.0 (04.01) Profile/MIDP-1.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3200/1.0 (4.18) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3200/1.0 () Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3220/2.0 (03.30) Profile/MIDP-2.0 Configuration/CLDC-1.1 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3410" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3510i/1.0 (04.01) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3510i/1.0 (04.01) Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/5.1.1.5a (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3510i/1.0 (04.44) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3510i/1.0 (05.30) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650/1.0 (4.13) SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650/1.0 (4.17) SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/5.1.2.7 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6010/1.0 (8.18) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6100" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6100/1.0 (05.16)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6100/1.0 (05.16) Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/1.1 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6100/1.0 (05.16) Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/mainline (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600/1.0 (3.42.1) SymbianOS/7.0s Series60/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600/1.0 (3.42.1) SymbianOS/7.0s Series60/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600/1.0 (4.09.1) SymbianOS/7.0s Series60/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600/1.0 (4.09.1) SymbianOS/7.0s Series60/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600/1.0 SymbianOS" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6610/1.0 (5.63) Profile/MIDP-1.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6610I/1.0 (3.10) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6610I/1.0 (3.10) Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/5.1.2.7 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6630" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6630/1.0 (3.45.113) SymbianOS/8.0 Series60/2.6 Profile/MIDP-2.0 Configuration/CLDC-1.1 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6800" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia7250/1.0 (3.12) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia7250/1.0 (3.14)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia7610/2.0 (3.0417.0ch) Symbian" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia7650" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia7650/1.0 SymbianOS/6.1 Series60/0.9 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "NokiaN-Gage/1.0 (4.03) SymbianOS/6.1 Series60/0.9 Profile/MIDP-1.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "NP/0.1 (NP; http://www.nameprotect.com; npbot@nameprotect.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; NPT 0.0 beta)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.01-beta (Nutch; http://www.nutch.org/docs/en/bot.html; nutch-agent@lists.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.03-dev (Nutch; http://www.nutch.org/docs/bot.html; nutch-agent@lists.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.03-dev (Nutch; http://www.nutch.org/docs/en/bot.html; nutch-agent@lists.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.06-dev (bot; http://www.nebel.de:8080/en/bot.html; nutch-agent@nebel.de)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.06-dev (bot; http://www.nebel.de/bot.html; nutch-agent@nebel.de)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.06-dev (Nutch; http://www.nutch.org/docs/en/bot.html; jagdeepssandhu@hotmail.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.06-dev (Nutch; http://www.nutch.org/docs/en/bot.html; nutch-agent@lists.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.06-dev (Nutch; http://www.s14g.com/en/search.html; travelbot@s14g.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchOSUOSL/0.05-dev (Nutch; http://www.nutch.org/docs/en/bot.html; nutch-agent@lists.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Nutscrape/1.0 (CP/M; 8-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Nutscrape/9.0 (CP/M; 8-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SEC-SGHC225-C225UVDH1-NW.Browser3.01 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NWSpider 0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ObjectsSearch/0.01 (ObjectsSearch; http://www.ObjectsSearch.com/bot.html; support@thesoftwareobjects.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ObjectsSearch/0.06 (ObjectsSearch; http://www.ObjectsSearch.com/bot.html; support@thesoftwareobjects.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ObjectsSearch/0.07 (ObjectsSearch; http://www.ObjectsSearch.com/bot.html; support@thesoftwareobjects.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows 2000)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows 2000) Webster Pro V3.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows 2000) Webster Pro V3.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows 98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows 98) Webster Pro V3.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows NT 4.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 (compatible; OmniWeb/4.1.1-v423; Mac_PowerPC)" + family: "OmniWeb" + major: '4' + minor: '1' + patch: '1' + - user_agent_string: "Mozilla/4.5 (compatible; OmniWeb/4.3-v435; Mac_PowerPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Opera" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Opera/ (X11; Linux i686; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (BeOS R4.5;US) Opera 3.60 [en]" + family: "Opera" + major: '3' + minor: '60' + patch: + - user_agent_string: "Mozilla/3.0 (Windows 3.10;US) Opera 3.62 [en]" + family: "Opera" + major: '3' + minor: '62' + patch: + - user_agent_string: "Mozilla/4.71 (Windows 3.10; US) Opera 3.62 [en]" + family: "Opera" + major: '3' + minor: '62' + patch: + - user_agent_string: "Mozilla/4.71 (Windows 3.10;US) Opera 3.62 [en]" + family: "Opera" + major: '3' + minor: '62' + patch: + - user_agent_string: "Mozilla/4.71 (Windows 98;US) Opera 3.62 [en]" + family: "Opera" + major: '3' + minor: '62' + patch: + - user_agent_string: "Mozilla/4.72 (Windows 98;US) Opera 4.0 Beta 3 [en]" + family: "Opera" + major: '4' + minor: '0' + patch: + - user_agent_string: "Opera/4.02 (Windows 98; U) [en]" + family: "Opera" + major: '4' + minor: '02' + patch: + - user_agent_string: "Opera/4.03 (Windows NT 4.0; U)" + family: "Opera" + major: '4' + minor: '03' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh;US;PPC) Opera 5.0 [en]" + family: "Opera" + major: '5' + minor: '0' + patch: + - user_agent_string: "Opera/5.01 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '5' + minor: '01' + patch: + - user_agent_string: "Opera/5.02 (alpha 06; AmigaOS) [en]" + family: "Opera" + major: '5' + minor: '02' + patch: + - user_agent_string: "Opera/5.02 (Windows 98; U) [en]" + family: "Opera" + major: '5' + minor: '02' + patch: + - user_agent_string: "Opera/5.02 (Windows 98; U) [en]" + family: "Opera" + major: '5' + minor: '02' + patch: + - user_agent_string: "Opera/5.02 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '5' + minor: '02' + patch: + - user_agent_string: "Opera/5.02 (X11; U; Linux i686; en-US)" + family: "Opera" + major: '5' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [es]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows ME) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.1) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Opera/5.12 (Windows 2000; U) [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Opera/5.12 (Windows 98; U) [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Opera/5.12 (Windows NT 4.0; U) [fr]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Opera/5.12 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.18-4GB i686) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.18-4 i686) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC) Opera 6.0 [ja]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Symbian OS; Series 90) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows ME; U) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Opera/6.00 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '00' + patch: + - user_agent_string: "Opera/6.0 (Macintosh; PPC Mac OS X; U) [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Opera/6.0 (Windows 2000; U) [de]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Opera/6.0 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Opera/6.0 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Opera/6.0 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.01 [es]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows ME) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0) Opera 6.01 [en] WebWasher 3.3" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.01 [de]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.01 [es]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.78 (Windows 2000; U) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows XP; U) Opera 6.01 [en]\"" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Opera/6.01 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Opera/6.01 (Windows ME; U) [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Opera/6.01 (Windows XP; U) [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Opera/6.01 (Windows XP; U) [ru]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.02 [en]" + family: "Opera" + major: '6' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS) Opera 6.02 [en]" + family: "Opera" + major: '6' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Linux 2.4.26 i586; U) Opera 6.02 [en]" + family: "Opera" + major: '6' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.24 i686) Opera 6.03 [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux) Opera 6.03 [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.03 [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Linux 2.4.19-64GB-SMP i686; U) [de]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Linux 2.4.19 i686; U) [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (OpenBSD 3.2 i386; U) [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Windows ME; U) [ja]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Windows XP; U) [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.04 [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.04 [en-GB]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.04 [en-GB]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows ME) Opera 6.04 [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.04 [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 6.04 [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 2000; U) [en-GB]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 98; U) [en-GB]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows XP; U) [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.05 [de]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.05 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.05 [it]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.05 ~ [~ [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.05 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.05 [es]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.05 OCV2 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0) Opera 6.05 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.05 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.05 [hu]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 2000; U) Opera 6.05 [de]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/5.0 (Windows XP; U) Opera 6.05 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows 2000; U) [de]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows 98; U) [de]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows 98; U) [en] WebWasher 3.0" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows XP; U) [de]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows XP; U) [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.06 [de]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.06 [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.06 [bg]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.06 [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.06 [en] (www.proxomitron.de)" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.06 [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 2000; U) Opera 6.06 [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows 98; U) [de]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows 98; U) [en] (www.proxomitron.de)" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows XP; U) [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows XP; U) [ja]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.2 i386) Opera 6.1 [en]" + family: "Opera" + major: '6' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Nokia 6600;423) Opera 6.10 [de]" + family: "Opera" + major: '6' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Nokia 7650;424) Opera 6.10 [de]" + family: "Opera" + major: '6' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Series 60;424) Opera 6.10 [en]" + family: "Opera" + major: '6' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; FreeBSD 4.4-RELEASE i386) Opera 6.11 [en]" + family: "Opera" + major: '6' + minor: '11' + patch: + - user_agent_string: "Mozilla/5.0 (UNIX; U) Opera 6.11 [en]" + family: "Opera" + major: '6' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; FreeBSD 5.3-RC2 i386) Opera 6.12 [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.22 i686) Opera 6.12 [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; UNIX) Opera 6.12 [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.78 (FreeBSD 5.0-RELEASE-p7 i386; U) Opera 6.12 [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Opera/6.12 (FreeBSD 4.8-RELEASE i386; U) [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Opera/6.12 (UNIX; U) [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Nokia 6600;451) Opera 6.20 [en]" + family: "Opera" + major: '6' + minor: '20' + patch: + - user_agent_string: "Opera/7 (Windows 98; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Opera/7.x (compatible; Konqueror/2.2.2; Linux 2.8.4-rc1; X11; i686)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Opera/7.x (Windows NT 5.1; U) [hr]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0(DDIPOCKET;KYOCERA/AH-K3001V/1.1.17.65.000000/0.1/C100) Opera 7.0" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 2000) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 98) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows XP) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 Opera/7.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040114" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 2000; U) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Opera/7.00 (Windows NT 5.0; U)" + family: "Opera" + major: '7' + minor: '00' + patch: + - user_agent_string: "Opera/7.0 (Windows 2000; U) [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Opera/7.0 (Windows 2000; U) [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Opera/7.0 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 98) Opera 7.01 [en]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 98) Opera 7.01 [ru]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows ME) Opera 7.01 [en]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.01 [en]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.01 [en]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.01 [ru]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Opera/7.01 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 98) Opera 7.02 [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows ME) Opera 7.02 [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.02 [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.02 [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Opera/7.02 Bork-edition (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Opera/7.02 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 98) Opera 7.03 [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.03 [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.03 [ja]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.03 [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.03 [ru]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Opera/7.03 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Opera/7.03 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Opera/7.03 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Opera/7.03 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Opera/7.03 (Windows NT 5.0; U) [nl]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.10 [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.10 [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.10 [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Linux 2.4.20 i686; U) [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Windows ME; U) [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Windows NT 5.0; U) [en] (www.proxomitron.de)" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.4.18-bf2.4 i686) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.4.20-8 i686) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.4.26 i686) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.4.2 i386) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.6.6 i686) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.11 [es]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.11 [de]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.11 [es-ES]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.11 [pl]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.11 [ru]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/5.0 (Linux 2.4.20-openmosix-3 i686; U) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Linux 2.4.18-xfs i686; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Linux 2.4.20-gentoo-r1 i686; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Linux 2.6.3-4mdk i686; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.0; U) [es]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.0; U) [it]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.0; U) [pl]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.0; U) [ru]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.1; U) [es]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 95) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.20 [ja]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.20 [ru]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.20 [ja]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.20 [ru]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.20 [de]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.20 [sk]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.20 [ja]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Opera/7.20 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Opera/7.20 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Opera/7.20 (Windows NT 5.1; U) [røv]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/3.0 (Windows 98; U) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.21 [pl]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.21 [fi]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.21 [de]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.21 [pl]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.21 [ru]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.21 [zh-cn]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i586) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows 98; U) [de]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.0; U) [it]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.1; U) [fi]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.22 [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.22 [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.22 [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.22 [fr]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.22 [pl]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.22 [de]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.22 [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.22 [es-ES]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.22 [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.22 [fr]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.22 [de]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Opera/7.22 (Windows NT 5.0; U) [de] WebWasher 3.3" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Opera/7.22 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Opera/7.22 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Opera/7.22 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Opera/7.22 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Linux) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [es-LA]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [hu]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [nl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.23 [en] WebWasher 3.3" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.23 [es-LA]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.23 [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.23 [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.23 [fr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [fr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [it]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [ja]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [nb]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [sv]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [cs]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [es-LA]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [fr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [it]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [ja]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [nb]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [nl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [pt-BR]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [sv]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [zh-cn]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [zh-tw] WebWasher 3.3" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.23 [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.23 [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.23 [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.23 [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; SunOS sun4u) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; SunOS sun4u) Opera 7.23 [ja]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 4.0; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.0; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.78 (X11; FreeBSD i386; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Opera 7.23; Windows NT 5.1)" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows ME; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.23 [et]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (X11; FreeBSD i386; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (compatible; MSIE 6.0; X11; Linux i586) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Linux 2.4.24-ck1 i686; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows 98; U) [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows ME; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 4.0; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U)" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [es-LA]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [tr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [cs]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [da]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [es]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [es-LA]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [fi]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [fr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [ja]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [sv]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [tr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [zh-tw]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; FreeBSD i386; U) [bg]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i386; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [fi]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [sv]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; SunOS sun4u; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Qt embedded; Linux armv5tel; 640x480) Opera 7.30 [en]" + family: "Opera" + major: '7' + minor: '30' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Opera 7.30; Irax)" + family: "Opera" + major: '7' + minor: '30' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.0; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/3.0 (X11; SunOS sun4u; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Mac_PowerPC) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 2000; Opera 7.50 [en])" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.50 [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.50 [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.50 [sv]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.50 [de]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.50 [IT]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.50 [pl]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.50 [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.50 [de] (www.proxomitron.de)" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.50 [es-ES]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; SunOS sun4u) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.78 (Windows 98; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.0; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.78 (X11; Linux i686; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.50 [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.50 [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (X11; FreeBSD i386; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.50 [es-LA]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Macintosh; U; PPC Mac OS X 10.3.3; en-US; rv:1.1 ) via HTTP/1.0 offshore.unitedbanks.org/" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows 95; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows 98; U) [en-US]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.0; U) [cs]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.0; U) [pl]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.0; U) [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.1; U) [en-GB]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (X11; FreeBSD i386; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/3.0 (X11; Linux i686; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.51 [cs]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.51 [ru]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.51 [de]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux ppc) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.78 (X11; Linux i686; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/5.0 (Windows ME; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Linux) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Mac_PowerPC; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows 95; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows 98; U) [de]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows ME; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 4.0; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.1; U) [fr]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (X11; Linux i686; U) [de]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (X11; Linux i686; U) [fi]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (X11; SunOS sun4u; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.52 [pl]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.78 (X11; Linux i686; U) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Macintosh; PPC Mac OS X; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.0; U) [en] WebWasher 3.3" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [nb]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.53 [da]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.53 [ja]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.53 [de]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.53 [es-ES]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.53 [ja]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.0; U) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.0; U) [ja]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.1; U) [ja]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows XP; U) [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/3.0 (Windows 98; U) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.0; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.54 [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.54 [sv]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 95) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54 [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54 [nb]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54 [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54u1 [nl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.54u1 [hu]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [fi]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [IT]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54u1 [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54u1 [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [bg]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [cs]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [da]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [de],gzip(gfe) (via translate.google.com)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [et]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [fi]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [hu]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [it]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [IT]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [nb]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [nl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [pt-BR]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54u1 [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54u1 [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.54 [ru]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.54 [it]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; SunOS sun4u) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.78 (X11; Linux i686; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; PPC Mac OS X; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows ME; U) Opera 7.54 [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.54 [it]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.54u1 [en] WebWasher 3.0" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54 [ca]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54 [sv]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54u1 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (X11; FreeBSD i386; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.54 [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux x86_64; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Amiga) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (AmigaOS 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (FreeBSD; U)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Linux 2.4.18-xfs i686; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Linux) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Macintosh; PPC Mac OS X; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera 7.54 (Macintosh; U; PPC Mac OS X v10.4 Tiger ) via HTTP/1.0 deep.space.star-travel.org/" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows 98; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows ME; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 4.0; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 4.0; U) [en] WebWasher 2.2.1" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.0; U) [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [hu]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [pt-BR]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows; U)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Unix; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 95; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 98; U) [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 98; U) [hu]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 98; U) [nl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 98; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows ME; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows ME; U) [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 4.0; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 4.0; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 4.0; U) [es-ar]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [fi]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U; have a nice day :) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U; have a nice day;) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [sv]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [cs]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [hu]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [it]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [IT]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [nb]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [nl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [ru]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [sv]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows; U)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; FreeBSD i386; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i386; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i586; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [cs]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [nl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [sv]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; SunOS sun4u; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; SunOS sun4u; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; U; Linux i686; fr-FR; rv:1.5)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.60 [de] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.60 [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; en) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; en) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; es) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.60 [en]" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.60 [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.60 [nl] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; pl) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; IT) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.60 [de] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.60 [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.60 [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; pl) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U; en) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.60 [de] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.60 [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U; pl) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera 7.60 (FreeBSD i686; U) [en] via HTTP/1.0 foot.fetish-expert.org/" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera 7.60 (Linux 2.4.10-4GB i686; U)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera 7.60 (Linux 2.4.8-26mdk i686; U) [en] FreeSurf tmfweb.nl v1.1 via HTTP/1.0 vienna.unitedworldcouncil.org/" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 preview 4 (Mac OS X 10.3)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows 98; U; pl)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera 7.60 (Windows NT 4.0; U) [en] via HTTP/1.0 l33t0-HaX0r.hiddenip.com/" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.0; U; en)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.0; U; ja)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.0; U; ja),gzip(gfe) (via translate.google.com)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.0; U; pl)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U; de)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U) [de] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U; en)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U) [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U) [pl] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.2; U; en)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.2; U) [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.2; U) [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera 7.60 (X11; Linux i386; U) [en] via HTTP/1.0 evil-uncle.trojanchecker.com/" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (X11; Linux i686; U; en)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Mac_PowerPC Mac OS X; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; de) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; en) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; cs) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; de) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; hu) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; en) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; IT) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; pl) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux ppc; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; ru) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.00 (Windows 98; U; de)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.0; U)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.0; U; de)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.0; U; en)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.0; U; pl)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; bg)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; cs)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; de)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; en)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; es)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; Mockingbird)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.2; U; en)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows; U)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.0 (Macintosh; PPC Mac OS X; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows 98; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows ME; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows NT 5.0; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows NT 5.1; U; de)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows NT 5.1; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows NT 5.1; U; pl)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows NT 5.2; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (X11; Linux i686; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (X11; Linux i686; U; pt-BR)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Opera 8.4; Windows ME; Maxthon; .NET CLR 1.1.4322)" + family: "Opera" + major: '8' + minor: '4' + patch: + - user_agent_string: "Operah" + family: "Other" + major: + minor: + patch: + - user_agent_string: "OZ Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "P3P Client" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PenguinFear (compatible; windows ce;; Windows NT 5.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PHILIPS-Fisio311/2.1 UP/4.1.19m" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PHP/4.2.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PHP/4.2.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PhpDig/PHPDIG_VERSION (+http://www.phpdig.net/robot.php)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PHP version tracker" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Pike HTTP client) Pike/7.6.25" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "PinkSock/1.0 (eComStation 1.2; en-CA; rv:0.4.9) PinkSock/20040416" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PinkSock/1.1 [en] (X11; U; SunOS 5.9 i86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PinkSock/1.2 [en_CA] (OpenBeOS 0.2 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PinkSock/1.3 [en_CA] (X11; U; SunOS 5.10 i86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PinkSock/1.4 [en_CA] (16-bit; U; DR-DOS 7.22)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PinkSock/1.5 [en_CA] (X11R6.7.0; U; FreeBSD 4.10-RELEASE)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "pipeLiner/0.10 (PipeLine Spider; http://www.pipeline-search.com/webmaster.html)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "POE-Component-Client-HTTP/0.510 (perl; N; POE; en; rv:0.510)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Popdexter/1.0 (http://www.popdex.com/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "portalmmm/2.0_M341i(c10;TB)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Powermarks/3.5; Windows 95/98/2000/NT)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Privoxy/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Privoxy/3.0 (Anonymous)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Program Shareware 1.0.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Progressive Download" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Proxomitron (www.proxomitron.de)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "puf/0.93.2a (Linux 2.4.20-19.9; i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Python-urllib/1.15" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Python-urllib/2.0a1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Python-urllib/2.0a1, Dowser/0.26 (http://dowser.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Qarp-1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ReadAheadWebBrowserHost" + family: "Other" + major: + minor: + patch: + - user_agent_string: "RealDownload/4.0.0.40" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Reaper/2.07 (+http://www.sitesearch.ca/reaper)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "RPT-HTTPClient/0.3-3E" + family: "Other" + major: + minor: + patch: + - user_agent_string: "RT-browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SA/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Safari" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/01 (KHTML, like Gecko) Safari/01" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; cs-cz) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (macintosh; U; PPC mac OS X; en) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/106.2 (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/103u (KHTML, like Gecko) Safari/100.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/106.2 (KHTML, like Gecko) Safari/100.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/106.2 (KHTML, like Gecko) Safari/100.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/106.2 (KHTML, like Gecko) Safari/100.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Safari 1.2 (Macintosh; U; PPC Mac OS X; en-us)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/146.1 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/124 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/185 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/124 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fi-fi) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; is-is) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; el-gr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; da-dk) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-at) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-ca) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-ca) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-ca) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; he-il) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; is-is) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; no-no) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; th-th) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; zh-tw) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; zh-tw) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0; 00) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.2.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; is-is) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ru-ru) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.4.2 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; is-is) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; no-no) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pt-pt) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/175 (KHTML, like Gecko) Safari/1.3" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/146 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/164 (KHTML, like Gecko) Safari/164" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/168 (KHTML, like Gecko) Safari/168" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/168 (KHTML, like Gecko) Safari/168" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/168 (KHTML, like Gecko) Safari/168" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/168 (KHTML, like Gecko) Safari/168" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/168 (KHTML, like Gecko) Safari/168" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/172 (KHTML, like Gecko) Safari/172" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/176 (KHTML, like Gecko) Safari/176" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/179 (KHTML, like Gecko) Safari/179" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/185 (KHTML, like Gecko) Safari/185" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/401 (KHTML, like Gecko) Safari/401" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/403 (KHTML, like Gecko) Safari/403" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/405 (KHTML, like Gecko) Safari/405" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/412 (KHTML, like Gecko) Safari/412" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/48 (like Gecko) Safari/48" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/64 (KHTML, like Gecko) Safari/64" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/73 (KHTML, like Gecko) Safari/73" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/85 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/85 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win16; en-US; rv:1.7) Safari/85.5" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.6" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.6" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.6" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.6" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/225 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sa) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppeWebKit/XX (KHTML, like Gecko) Safari/YY" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/XX (KHTML, like Gecko) Safari/YY" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SafariBookmarkChecker/1.27 (+http://www.coriolis.ch/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; SaferSurf; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; SaferSurf; DigExt)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Satan 666 (7th level of Hell)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "savvybot/0.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Search-Channel" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SecretBrowser/007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K Tron (AmigaOS; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K Tron (AmigaOS; alpha/06; AmigaOS 3.5; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K Tron (AmigaOS; alpha/06; AmigaOS; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K Tron (AmigaOS; alpha/06; Win98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K-Tron Systems" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K-Tron Systems(compatible; MSIE 6.0; Matrix; SEK-Tron Systems; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "SEK Tron (AmigaOS; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K-Tron Systems(compatible; MSIE 6.0; Matrix; SEK-Tron Systems; AmigaOS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "S.E.K-Tron Systems(SEK-Tron; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SHARP-TQ-GX10" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SHARP-TQ-GX30" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Shockwave Flash" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ShowLinks/1.0 libwww/5.4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SIE-S55/16" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Simpy/1.1 (Simpy; http://www.simpy.com/?ref=bot; feedback at simpy dot com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SISLink" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SiteBar/3.2.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Slackware)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; SmartPhone; Symbian OS/1.1.0) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Smurf Power" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Snoopy v1.01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Snowstorm/0.1.0 (windows; U; SnowStep0.6.0; en-us) Gecko/20201231" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Solar Conflict (www.solarconflict.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "sony ericsson" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP800/" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP900/" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP900/ UP.Link/5.1.2.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT230/R101 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT306/R101 UP.Link/1.1 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT68/R502 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Sopheus Project/0.01 (Nutch; http://www.thenetplanet.com; info@thenetplanet.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SpaceBison/0.01 [fu] (Win67; X; Lolzor)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SpaceBison/0.01 [fu] (Win67; X; ShonenKnife)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Space Bison/0.02 [fu] (Win67; X; SK)" + family: "Space Bison" + major: '0' + minor: '02' + patch: + - user_agent_string: "Space Bison/0.69 [fu] (Win72; incompatible)" + family: "Space Bison" + major: '0' + minor: '69' + patch: + - user_agent_string: "SpiderMan 3.0.1-2-11-111 (CP/M;8-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SquidClamAV_Redirector 1.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Squid-Prefetch" + family: "Other" + major: + minor: + patch: + - user_agent_string: "StackRambler/2.0 (MSIE incompatible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "StarDownloader/1.44" + family: "Other" + major: + minor: + patch: + - user_agent_string: "StarDownloader/1.52" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Steeler/2.0 (http://www.tkl.iis.u-tokyo.ac.jp/~crawler/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; SuperCleaner 2.81; Windows NT 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Supergrass (GNU/Windows; U) [sr]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SuperMarioBrowser/3.0 [en] (NintendoOS 0.4.27)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SuperMarioBrowser/3.0 (WarioOS; U; WarioWare 2.1.4; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SymbianOS/6.1 Series60/1.2 Profile/MIDP-" + family: "Nokia OSS Browser" + major: '1' + minor: '2' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Synapse)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Teleport Pro/1.29" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Teleport Pro/1.29.1590" + family: "Other" + major: + minor: + patch: + - user_agent_string: "TheBlacksheepbrowser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "theConcept/1.0 (Macintosh)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "theConcept/1.1 (Macintosh)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Toaster/2.0 (X11; U; BeOS i786; en, de; rv:7.8.9) Gecko/20250223 Toaster/2.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Tutorial Crawler 1.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "TygoProwler (http://www.tygo.com/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "UP.Browser/3.1.02-SC01 UP.Link/5.0.2.9 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '3' + minor: '1' + patch: '02' + - user_agent_string: "OWG1 UP/4.1.20a UP.Browser/4.1.20a-XXXX UP.Link/5.1.2.12 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '20' + - user_agent_string: "QC2135 UP.Browser/4.1.22b UP.Link/4.2.1.8 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '22' + - user_agent_string: "MOT-85/01.04 UP.Browser/4.1.26m.737 UP.Link/5.1.2.12 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '26' + - user_agent_string: "MOT-A-0A/00.06 UP.Browser/4.1.27a1 UP.Link/4.2.3.5h" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '27' + - user_agent_string: "MOT-A-2D/00.02 UP.Browser/4.1.27a1 UP.Link/5.1.2.12 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '27' + - user_agent_string: "MOT-A-86/00.00 UP.Browser/4.1.27a1 UP.Link/4.2.3.5h (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '27' + - user_agent_string: "MOT-A-86/00.00 UP.Browser/4.1.27a1 UP.Link/5.1.2.12 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '27' + - user_agent_string: "Motorola-T33/1.5.1a UP.Browser/5.0.1.7.c.2 (GUI) (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '5' + minor: '0' + patch: '1' + - user_agent_string: "Alcatel-BG3/1.0 UP.Browser/5.0.3.1.2 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '5' + minor: '0' + patch: '3' + - user_agent_string: "KDDI/CA23/UP. Browser/6.0.2.254 (GUI) MMP/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Panasonic-G60/1.0 UP.Browser/6.1.0.7 MMP/1.0 UP.Browser/6.1.0.7 (GUI) MMP/1.0 UP.Link/5.1.1a (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SAGEM-myX-5m/1.0 UP.Browser/6.1.0.6.1.c.3 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SAMSUNG-SGH-E700/BSI UP.Browser/6.1.0.6 (GUI) MMP/1.0" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SAMSUNG-SGH-E700/BSI UP.Browser/6.1.0.6 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SAMSUNG-SGH-E700-OLYMPIC2004/1.0 UP.Browser/6.1.0.6 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SAMSUNG-SGH-X600/K3 UP.Browser/6.1.0.6 (GUI) MMP/1.0" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-C60/12 UP.Browser/6.1.0.5.c.6 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-M55/11 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Browser/6.1.0.7.3 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-MC60/10 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Browser/6.1.0.7.3 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-MC60/10 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Browser/6.1.0.7.3 (GUI) MMP/1.0 UP.Link/5.1.1.5a" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-S55/11 UP.Browser/6.1.0.5.c.2 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-S55/20 UP.Browser/6.1.0.5.c.6 (GUI) MMP/1.0 UP.Link/1.1 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "UP.Browser/6.1.0.1.140 (Google CHTML Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "KDDI-HI32 UP.Browser/6.2.0.5 (GUI) MMP/2.0" + family: "UP.Browser" + major: '6' + minor: '2' + patch: '0' + - user_agent_string: "SHARP-TQ-GX20/1.0 UP.Browser/6.2.0.1.185 (GUI) MMP/2.0" + family: "UP.Browser" + major: '6' + minor: '2' + patch: '0' + - user_agent_string: "OPWV-SDK/62 UP.Browser/6.2.2.1.208 (GUI) MMP/2.0" + family: "UP.Browser" + major: '6' + minor: '2' + patch: '2' + - user_agent_string: "VM4050/132.037 UP.Browser/6.2.2.4.e.1.100 (GUI) MMP/2.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" + family: "UP.Browser" + major: '6' + minor: '2' + patch: '2' + - user_agent_string: "LGE-VX7000/1.0 UP.Browser/6.2.3.1.174 (GUI) MMP/2.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "SIE-CX65/12 UP.Browser/7.0.0.1.c.3 (GUI) MMP/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '7' + minor: '0' + patch: '0' + - user_agent_string: "SIE-S65/25 UP.Browser/7.0.0.1.c.3 (GUI) MMP/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.1" + family: "UP.Browser" + major: '7' + minor: '0' + patch: '0' + - user_agent_string: "SEC-SGHX427M UP.Link/1.1 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Uptimebot" + family: "Other" + major: + minor: + patch: + - user_agent_string: "UptimeBot" + family: "Other" + major: + minor: + patch: + - user_agent_string: "User-Agent: Mozilla/5.0 (Windows; U; Windows; de-DE; rv:1.7.5)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "UserAgent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040329" + family: "Other" + major: + minor: + patch: + - user_agent_string: "User-Agent: S.E.K Tron (AmigaOS; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Veczilla/0.35beta (X11; U; UNICOS/mk 21164a(EV5.6) Cray T3E; en-US; m18) Gecko/20020202 Netscape6/6.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Veczilla/0.35beta (X11; U; UNICOS/mk 21164a(EV5.6) Cray T3E; en-US; m18) Gecko/20040329" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.5 (compatible; Voyager; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "W32/Trojan.Coced.226" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Emacs-W3/4.0pre.46 URL/p4.0pre.46 (i386-suse-linux; X11)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.3.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.3.1+cvs-1.411" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.3.1+cvs-1.414" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.3.2+mee-p24-19+moe-1.5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.4.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.4.1-m17n-20030308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.4.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.5+cvs-1.916" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.5 (FreeBSD),gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.5.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WannaBe (Macintosh; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Wap" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WAP" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Web Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; WebCapture 2.0; Auto; Windows)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; WebCapture 2.0; Windows)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebCatSv" + family: "Other" + major: + minor: + patch: + - user_agent_string: "webcollage/1.114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebForm 1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (compatible; WebGod 9.1; Windows NT 6.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebHopper" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; WebMon 1.0.10; Windows 98 SE)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebPix 1.0 (www.netwu.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebRescuer v0.2.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebStripper/2.20" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebStripper/2.58" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 WebTV/1.2 (compatible; MSIE 2.0)" + family: "IE" + major: '2' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; WebTV/2.6)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 WebTV/2.6 (compatible; MSIE 4.0)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "WebZIP/4.1 (http://www.spidersoft.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "wget 1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Wget/1.8.2 modified" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Wget/1.9+cvs-stable (Red Hat modified)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.00; Window 98)" + family: "IE" + major: '5' + minor: '00' + patch: + - user_agent_string: "WinHTTP Example/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WinWAP-PRO/3.1 (3.1.5.190) UP.Link/5.1.2.5 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WM2003/1 (Windows CE 3.0; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WordPress/1.2.1 PHP/4.3.9-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WorldWideWeb-X/3.2 (+Web Directory)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Wotbox/0.7-alpha (bot@wotbox.com; http://www.wotbox.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Wotbox/alpha0.6 (bot@wotbox.com; http://www.wotbox.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "www.WebSearch.com.au" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 9.0b; Xbox-OS2) Obsidian" + family: "IE" + major: '9' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 7.0b; Xbox-OS2) Obsidian" + family: "IE" + major: '7' + minor: '0' + patch: + - user_agent_string: "XBoX 64 (NVidea GForce 3 Architecture)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Xtreme Browser/0.14 (Linux; U) [i386-en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Yahoo-MMAudVid/1.0 (mms dash mmaudvidcrawler dash support at yahoo dash inc dot com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Yandex/1.01.001 (compatible; Win16; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "YottaShopping_Bot/4.12 (+http://www.yottashopping.com) Shopping Search Engine" + family: "Other" + major: + minor: + patch: diff --git a/node_modules/karma/node_modules/useragent/test/fixtures/static.custom.yaml b/node_modules/karma/node_modules/useragent/test/fixtures/static.custom.yaml new file mode 100644 index 00000000..bacf1a08 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/test/fixtures/static.custom.yaml @@ -0,0 +1,13 @@ +test_cases: + + - user_agent_string: 'curl/7.12.1 (i686-redhat-linux-gnu) libcurl/7.12.1 OpenSSL/0.9.7a zlib/1.2.1.2 libidn/0.5.6' + family: 'cURL' + major: '7' + minor: '12' + patch: '1' + + - user_agent_string: 'Wget/1.10.1 (Red Hat modified)' + family: 'Wget' + major: '1' + minor: '10' + patch: '1' diff --git a/node_modules/karma/node_modules/useragent/test/fixtures/testcases.yaml b/node_modules/karma/node_modules/useragent/test/fixtures/testcases.yaml new file mode 100644 index 00000000..d60c8863 --- /dev/null +++ b/node_modules/karma/node_modules/useragent/test/fixtures/testcases.yaml @@ -0,0 +1,389 @@ +test_cases: + + - user_agent_string: 'Mozilla/5.0 (X11i; Linux; C) AppleWebKikt/533.3 (KHTML, like Gecko) QtCarBrowser Safari/533.3' + family: 'QtCarBrowser' + major: '1' + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.8+ (KHTML, like Gecko) Version/6.0 Safari/536.25' + family: 'WebKit Nightly' + major: '537' + minor: '8' + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22' + family: 'WebKit Nightly' + major: '534' + minor: + patch: + + - user_agent_string: 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)' + family: 'FacebookBot' + major: '1' + minor: '1' + patch: + + - user_agent_string: 'Pingdom.com_bot_version_1.4_(http://www.pingdom.com/)' + family: 'PingdomBot' + major: '1' + minor: '4' + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22' + family: 'WebKit Nightly' + major: '534' + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1+ (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22' + family: 'WebKit Nightly' + major: '537' + minor: '1' + patch: + + - user_agent_string: 'Mozilla/5.0 (Linux x86_64) AppleWebKit/534.26+ WebKitGTK+/1.4.1 luakit/f3a2dbe' + family: 'LuaKit' + major: + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20110408 conkeror/0.9.3' + family: 'Conkeror' + major: '0' + minor: '9' + patch: '3' + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20110302 Conkeror/0.9.2 (Debian-0.9.2+git100804-1)' + family: 'Conkeror' + major: '0' + minor: '9' + patch: '2' + + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.17) Gecko/20110414 Lightning/1.0b3pre Thunderbird/3.1.10' + family: 'Lightning' + major: '1' + minor: '0' + patch: 'b3pre' + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.17) Gecko/20110414 Thunderbird/3.1.10 ThunderBrowse/3.3.5' + family: 'ThunderBrowse' + major: '3' + minor: '3' + patch: '5' + + - user_agent_string: 'Mozilla/5.0 (Windows; U; en-US) AppleWebKit/531.9 (KHTML, like Gecko) AdobeAIR/2.5.1' + family: 'AdobeAIR' + major: '2' + minor: '5' + patch: '1' + + - user_agent_string: 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' + family: 'Googlebot' + major: '2' + minor: '1' + patch: + + - user_agent_string: 'Mozilla/5.0 YottaaMonitor;' + family: 'YottaaMonitor' + major: + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) RockMelt/0.8.34.841 Chrome/6.0.472.63 Safari/534.3' + family: 'RockMelt' + major: '0' + minor: '8' + patch: '34' + + - user_agent_string: 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20110417 IceCat/4.0' + family: 'IceCat' + major: '4' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; nl-NL) AppleWebKit/534.3 (KHTML, like Gecko) WeTab-Browser Safari/534.3' + family: 'WeTab' + major: + minor: + patch: + + - user_agent_string: 'Mozilla/4.0 (compatible; Linux 2.6.10) NetFront/3.3 Kindle/1.0 (screen 600x800)' + family: 'Kindle' + major: '1' + minor: '0' + patch: + + - user_agent_string: 'Opera/9.80 (Android 3.2; Linux; Opera Tablet/ADR-1106291546; U; en) Presto/2.8.149 Version/11.10' + family: 'Opera Tablet' + major: '11' + minor: '10' + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) FireWeb/1.0.0.0' + family: 'FireWeb' + major: '1' + minor: '0' + patch: '0' + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Comodo_Dragon/4.1.1.11 Chrome/4.1.249.1042 Safari/532.5' + family: 'Comodo Dragon' + major: '4' + minor: '1' + patch: '1' + + - user_agent_string: 'Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5' + family: 'Mobile Safari' + major: '5' + minor: '0' + patch: '2' + + - user_agent_string: 'Mozilla/5.0 (Linux; U; Android 3.0.1; en-us; GT-P7510 Build/HRI83) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' + family: 'Android' + major: '3' + minor: '0' + patch: '1' + + - user_agent_string: 'Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.58 Safari/534.6 TouchPad/1.0' + family: 'webOS TouchPad' + major: '1' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; SAMSUNG; SGH-i917)' + family: 'IE Mobile' + major: '7' + minor: '0' + patch: + + + - user_agent_string: 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Safari/530.17 Skyfire/2.0' + family: 'Skyfire' + major: '2' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.8+ (KHTML, like Gecko) Version/0.0.1 Safari/534.8+' + family: 'Blackberry WebKit' + major: '1' + minor: '0' + patch: '0' + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16' + family: 'Chromium' + major: '10' + minor: '0' + patch: '648' + + - user_agent_string: 'Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20110407 Firefox/4.0.3 PaleMoon/4.0.3' + family: 'Pale Moon (Firefox Variant)' + major: '4' + minor: '0' + patch: '3' + + - user_agent_string: 'Opera/9.80 (Series 60; Opera Mini/6.24455/25.677; U; fr) Presto/2.5.25 Version/10.54' + family: 'Opera Mini' + major: '6' + minor: '24455' + patch: + + - user_agent_string: 'Mozilla/5.0 (X11; Linux i686 (x86_64); rv:2.0b4) Gecko/20100818 Firefox/4.0b4' + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: 'b4' + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.04 (lucid) Firefox/3.6.12' + family: 'Firefox' + major: '3' + minor: '6' + patch: '12' + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.1pre) Gecko/20090717 Ubuntu/9.04 (jaunty) Shiretoko/3.5.1pre' + family: 'Firefox (Shiretoko)' + major: '3' + minor: '5' + patch: '1pre' + + - user_agent_string: 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0b8pre) Gecko/20101031 Firefox-4.0/4.0b8pre' + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: 'b8pre' + + - user_agent_string: 'Mozilla/5.0 (X11; U; BSD Four; en-US) AppleWebKit/533.3 (KHTML, like Gecko) rekonq Safari/533.3' + family: 'Rekonq' + major: + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.34 (KHTML, like Gecko) rekonq/1.0 Safari/534.34' + family: 'Rekonq' + major: '1' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux; de-DE) AppleWebKit/527 (KHTML, like Gecko, Safari/419.3) konqueror/4.3.1' + family: 'Konqueror' + major: '4' + minor: '3' + patch: '1' + + - user_agent_string: 'SomethingWeNeverKnewExisted' + family: 'Other' + major: + minor: + patch: + + - user_agent_string: 'Midori/0.2 (X11; Linux; U; en-us) WebKit/531.2 ' + family: 'Midori' + major: '0' + minor: '2' + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.3a1) Gecko/20100208 MozillaDeveloperPreview/3.7a1 (.NET CLR 3.5.30729)' + family: 'MozillaDeveloperPreview' + major: '3' + minor: '7' + patch: 'a1' + + - user_agent_string: 'Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.24 Version/10.53' + family: 'Opera' + major: '10' + minor: '53' + patch: + + - user_agent_string: 'Opera/9.80 (S60; SymbOS; Opera Mobi/275; U; es-ES) Presto/2.4.13 Version/10.00' + family: 'Opera Mobile' + major: '10' + minor: '00' + patch: + + - user_agent_string: 'Mozilla/5.0 (webOS/1.2; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Desktop/1.0' + family: 'webOSBrowser' + major: '1' + minor: '2' + patch: + + - user_agent_string: 'Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10' + family: 'Mobile Safari' + major: '4' + minor: '0' + patch: '4' + + - user_agent_string: 'Mozilla/5.0 (SAMSUNG; SAMSUNG-GT-S8500/S8500XXJEE; U; Bada/1.0; nl-nl) AppleWebKit/533.1 (KHTML, like Gecko) Dolfin/2.0 Mobile WVGA SMM-MMS/1.2.0 OPN-B' + family: 'Dolfin' + major: '2' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; BOLT/2.101) AppleWebKit/530 (KHTML, like Gecko) Version/4.0 Safari/530.17' + family: 'BOLT' + major: '2' + minor: '101' + patch: + + # Safari + - user_agent_string: 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3' + family: 'Safari' + major: + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5' + family: 'Safari' + major: '5' + minor: '0' + patch: '2' + + # BlackBerry devices + - user_agent_string: 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en-GB) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.141 Mobile Safari/534.1+' + family: 'Blackberry WebKit' + major: '6' + minor: '0' + patch: '0' + + - user_agent_string: 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Version/6.0.0.91 Mobile Safari/534.1 ' + family: 'Blackberry WebKit' + major: '6' + minor: '0' + patch: '0' + + # Chrome frame + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; chromeframe; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; Sleipnir 2.8.5)3.0.30729)' + js_ua: "{'js_user_agent_string': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Chrome/2.0.169.1 Safari/530.1'}" + family: 'Chrome Frame (Sleipnir 2)' + major: '2' + minor: '0' + patch: '169' + + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; chromeframe; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)' + js_ua: "{'js_user_agent_string': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Chrome/2.0.169.1 Safari/530.1'}" + family: 'Chrome Frame (IE 8)' + major: '2' + minor: '0' + patch: '169' + + # Chrome Frame installed but not enabled + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; chromeframe; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)' + js_ua: "{'js_user_agent_string': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; chromeframe; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)'}" + family: 'IE' + major: '8' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; .NET CLR 2.0.50727; .NET CLR 1.1.4322)' + js_ua: "{'js_user_agent_string': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 1.1.4322)', 'js_user_agent_family': 'IE Platform Preview', 'js_user_agent_v1': '9', 'js_user_agent_v2': '0', 'js_user_agent_v3': '1'}" + family: 'IE Platform Preview' + major: '9' + minor: '0' + patch: '1' + + - user_agent_string: 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.1.0-80) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true' + family: 'Silk' + major: '1' + minor: '1' + patch: '0-80' + +# - user_agent_string: 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; XBLWP7; ZuneWP7)' +# family: 'IE Mobile' +# major: '9' +# minor: '0' +# patch: + + - user_agent_string: 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i917)' + family: 'IE Mobile' + major: '9' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i917)' + family: 'IE Mobile' + major: '9' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; chromeframe/11.0.660.0)' + family: 'Chrome Frame' + major: '11' + minor: '0' + patch: '660' + + - user_agent_string: 'PyAMF/0.6.1' + family: 'PyAMF' + major: '0' + minor: '6' + patch: '1' + + - user_agent_string: 'python-requests/0.14 CPython/2.6 Linux/2.6-43-server' + family: 'Python Requests' + major: '0' + minor: '14' + patch: + + - user_agent_string: 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0)' + family: 'IE' + major: '10' + minor: '0' + patch: diff --git a/node_modules/karma/node_modules/useragent/test/mocha.opts b/node_modules/karma/node_modules/useragent/test/mocha.opts new file mode 100644 index 00000000..bf0875dd --- /dev/null +++ b/node_modules/karma/node_modules/useragent/test/mocha.opts @@ -0,0 +1,4 @@ +--reporter spec +--ui bdd +--require should +--growl diff --git a/node_modules/karma/node_modules/useragent/test/parser.qa.js b/node_modules/karma/node_modules/useragent/test/parser.qa.js new file mode 100644 index 00000000..fda5434a --- /dev/null +++ b/node_modules/karma/node_modules/useragent/test/parser.qa.js @@ -0,0 +1,45 @@ +var useragent = require('../') + , should = require('should') + , yaml = require('yamlparser') + , fs = require('fs'); + +// run over the testcases, some might fail, some might not. This is just qu +// test to see if we can parse without errors, and with a reasonable amount +// of errors. +[ + 'testcases.yaml' + , 'static.custom.yaml' + , 'firefoxes.yaml' + , 'pgts.yaml' +].forEach(function (filename) { + var testcases = fs.readFileSync(__dirname +'/fixtures/' + filename).toString() + , parsedyaml = yaml.eval(testcases); + + testcases = parsedyaml.test_cases; + testcases.forEach(function (test) { + // we are unable to parse these tests atm because invalid JSON is used to + // store the useragents + if (typeof test.user_agent_string !== 'string') return; + + // these tests suck as the test files are broken, enable this to have about + // 40 more failing tests + if (test.family.match(/googlebot|avant/i)) return; + + // attempt to parse the shizzle js based stuff + var js_ua; + if (test.js_ua) { + js_ua = (Function('return ' + test.js_ua)()).js_user_agent_string; + } + + exports[filename + ': ' + test.user_agent_string] = function () { + var agent = useragent.parse(test.user_agent_string, js_ua); + + agent.family.should.equal(test.family); + // we need to test if v1 is a string, because the yamlparser transforms + // empty v1: statements to {} + agent.major.should.equal(typeof test.major == 'string' ? test.major : '0'); + agent.minor.should.equal(typeof test.minor == 'string' ? test.minor : '0'); + agent.patch.should.equal(typeof test.patch == 'string' ? test.patch : '0'); + } + }); +}); diff --git a/node_modules/karma/node_modules/useragent/test/parser.test.js b/node_modules/karma/node_modules/useragent/test/parser.test.js new file mode 100644 index 00000000..ab6473fe --- /dev/null +++ b/node_modules/karma/node_modules/useragent/test/parser.test.js @@ -0,0 +1,214 @@ +describe('useragent', function () { + 'use strict'; + + var useragent = require('../') + , ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.24 Safari/535.2"; + + it('should expose the current version number', function () { + useragent.version.should.match(/^\d+\.\d+\.\d+$/); + }); + + it('should expose the Agent interface', function () { + useragent.Agent.should.be.a('function'); + }); + + it('should expose the OperatingSystem interface', function () { + useragent.OperatingSystem.should.be.a('function'); + }); + + it('should expose the Device interface', function () { + useragent.Device.should.be.a('function'); + }); + + it('should expose the dictionary lookup', function () { + useragent.lookup.should.be.a('function'); + }); + + it('should expose the parser', function () { + useragent.parse.should.be.a('function'); + }); + + it('should expose the useragent tester', function () { + useragent.is.should.be.a('function'); + }); + + describe('#parse', function () { + it('correctly transforms everything to the correct instances', function () { + var agent = useragent.parse(ua); + + agent.should.be.an.instanceOf(useragent.Agent); + agent.os.should.be.an.instanceOf(useragent.OperatingSystem); + agent.device.should.be.an.instanceOf(useragent.Device); + }); + + it('correctly parsers the operating system', function () { + var os = useragent.parse(ua).os; + + os.toString().should.equal('Mac OS X 10.7.1'); + os.toVersion().should.equal('10.7.1'); + JSON.stringify(os).should.equal('{"family":"Mac OS X","major":"10","minor":"7","patch":"1"}'); + + os.major.should.equal('10'); + os.minor.should.equal('7'); + os.patch.should.equal('1'); + }); + + it('should not throw errors when no useragent is given', function () { + var agent = useragent.parse(); + + agent.family.should.equal('Other'); + agent.major.should.equal('0'); + agent.minor.should.equal('0'); + agent.patch.should.equal('0'); + + agent.os.toString().should.equal('Other'); + agent.toVersion().should.equal('0.0.0'); + agent.toString().should.equal('Other 0.0.0 / Other'); + agent.toAgent().should.equal('Other 0.0.0'); + JSON.stringify(agent).should.equal('{"family":"Other","major":"0","minor":"0","patch":"0","device":{"family":"Other"},"os":{"family":"Other"}}'); + }); + + it('should not throw errors on empty strings and default to unkown', function () { + var agent = useragent.parse(''); + + agent.family.should.equal('Other'); + agent.major.should.equal('0'); + agent.minor.should.equal('0'); + agent.patch.should.equal('0'); + + agent.os.toString().should.equal('Other'); + agent.toVersion().should.equal('0.0.0'); + agent.toString().should.equal('Other 0.0.0 / Other'); + agent.toAgent().should.equal('Other 0.0.0'); + JSON.stringify(agent).should.equal('{"family":"Other","major":"0","minor":"0","patch":"0","device":{"family":"Other"},"os":{"family":"Other"}}'); + }); + + it('should correctly parse chromes user agent', function () { + var agent = useragent.parse(ua); + + agent.family.should.equal('Chrome'); + agent.major.should.equal('15'); + agent.minor.should.equal('0'); + agent.patch.should.equal('874'); + + agent.os.toString().should.equal('Mac OS X 10.7.1'); + agent.toVersion().should.equal('15.0.874'); + agent.toString().should.equal('Chrome 15.0.874 / Mac OS X 10.7.1'); + agent.toAgent().should.equal('Chrome 15.0.874'); + JSON.stringify(agent).should.equal('{"family":"Chrome","major":"15","minor":"0","patch":"874","device":{"family":"Other"},"os":{"family":"Mac OS X","major":"10","minor":"7","patch":"1"}}'); + }); + }); + + describe('#fromJSON', function () { + it('should re-generate the Agent instance', function () { + var agent = useragent.parse(ua) + , string = JSON.stringify(agent) + , agent2 = useragent.fromJSON(string); + + agent2.family.should.equal(agent.family); + agent2.major.should.equal(agent.major); + agent2.minor.should.equal(agent.minor); + agent2.patch.should.equal(agent.patch); + + agent2.device.family.should.equal(agent.device.family); + + agent2.os.family.should.equal(agent.os.family); + agent2.os.major.should.equal(agent.os.major); + agent2.os.minor.should.equal(agent.os.minor); + agent2.os.patch.should.equal(agent.os.patch); + }); + + it('should also work with legacy JSON', function () { + var agent = useragent.fromJSON('{"family":"Chrome","major":"15","minor":"0","patch":"874","os":"Mac OS X"}'); + + agent.family.should.equal('Chrome'); + agent.major.should.equal('15'); + agent.minor.should.equal('0'); + agent.patch.should.equal('874'); + + agent.device.family.should.equal('Other'); + + agent.os.family.should.equal('Mac OS X'); + }); + }); + + describe('#is', function () { + var chrome = ua + , firefox = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0) Gecko/20100101 Firefox/8.0' + , ie = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; yie8)' + , opera = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; de) Opera 11.51' + , safari = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; da-dk) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1' + , ipod = 'Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5'; + + it('should not throw errors when called without arguments', function () { + useragent.is(); + useragent.is(''); + }); + + it('should correctly detect google chrome', function () { + useragent.is(chrome).chrome.should.equal(true); + useragent.is(chrome).webkit.should.equal(true); + useragent.is(chrome).safari.should.equal(false); + useragent.is(chrome).firefox.should.equal(false); + useragent.is(chrome).mozilla.should.equal(false); + useragent.is(chrome).ie.should.equal(false); + useragent.is(chrome).opera.should.equal(false); + useragent.is(chrome).mobile_safari.should.equal(false); + }); + + it('should correctly detect firefox', function () { + useragent.is(firefox).chrome.should.equal(false); + useragent.is(firefox).webkit.should.equal(false); + useragent.is(firefox).safari.should.equal(false); + useragent.is(firefox).firefox.should.equal(true); + useragent.is(firefox).mozilla.should.equal(true); + useragent.is(firefox).ie.should.equal(false); + useragent.is(firefox).opera.should.equal(false); + useragent.is(firefox).mobile_safari.should.equal(false); + }); + + it('should correctly detect internet explorer', function () { + useragent.is(ie).chrome.should.equal(false); + useragent.is(ie).webkit.should.equal(false); + useragent.is(ie).safari.should.equal(false); + useragent.is(ie).firefox.should.equal(false); + useragent.is(ie).mozilla.should.equal(false); + useragent.is(ie).ie.should.equal(true); + useragent.is(ie).opera.should.equal(false); + useragent.is(ie).mobile_safari.should.equal(false); + }); + + it('should correctly detect opera', function () { + useragent.is(opera).chrome.should.equal(false); + useragent.is(opera).webkit.should.equal(false); + useragent.is(opera).safari.should.equal(false); + useragent.is(opera).firefox.should.equal(false); + useragent.is(opera).mozilla.should.equal(false); + useragent.is(opera).ie.should.equal(false); + useragent.is(opera).opera.should.equal(true); + useragent.is(opera).mobile_safari.should.equal(false); + }); + + it('should correctly detect safari', function () { + useragent.is(safari).chrome.should.equal(false); + useragent.is(safari).webkit.should.equal(true); + useragent.is(safari).safari.should.equal(true); + useragent.is(safari).firefox.should.equal(false); + useragent.is(safari).mozilla.should.equal(false); + useragent.is(safari).ie.should.equal(false); + useragent.is(safari).opera.should.equal(false); + useragent.is(safari).mobile_safari.should.equal(false); + }); + + it('should correctly detect safari-mobile', function () { + useragent.is(ipod).chrome.should.equal(false); + useragent.is(ipod).webkit.should.equal(true); + useragent.is(ipod).safari.should.equal(true); + useragent.is(ipod).firefox.should.equal(false); + useragent.is(ipod).mozilla.should.equal(false); + useragent.is(ipod).ie.should.equal(false); + useragent.is(ipod).opera.should.equal(false); + useragent.is(ipod).mobile_safari.should.equal(true); + }); + }); +}); diff --git a/node_modules/karma/package.json b/node_modules/karma/package.json new file mode 100644 index 00000000..8e8af9bb --- /dev/null +++ b/node_modules/karma/package.json @@ -0,0 +1,392 @@ +{ + "name": "karma", + "description": "Spectacular Test Runner for JavaScript.", + "homepage": "http://karma-runner.github.io/", + "repository": { + "type": "git", + "url": "git://github.com/karma-runner/karma.git" + }, + "bugs": { + "url": "https://github.com/karma-runner/karma/issues" + }, + "keywords": [ + "karma", + "spectacular", + "runner", + "karma", + "js", + "javascript", + "testing", + "test", + "remote", + "execution" + ], + "author": { + "name": "Vojta Jína", + "email": "vojta.jina@gmail.com" + }, + "contributors": [ + { + "name": "Friedel Ziegelmayer", + "email": "friedel.ziegelmayer@gmail.com" + }, + { + "name": "taichi", + "email": "ryushi@gmail.com" + }, + { + "name": "Liam Newman", + "email": "bitwiseman@gmail.com" + }, + { + "name": "Shyam Seshadri", + "email": "shyamseshadri@gmail.com" + }, + { + "name": "Kim Joar Bekkelund", + "email": "kjbekkelund@gmail.com" + }, + { + "name": "Tim Cuthbertson", + "email": "tim@gfxmonk.net" + }, + { + "name": "Andrew Martin", + "email": "sublimino@gmail.com" + }, + { + "name": "Daniel Aleksandersen", + "email": "code@daniel.priv.no" + }, + { + "name": "Ilya Volodin", + "email": "ivolodin@vistaprint.com" + }, + { + "name": "Iristyle", + "email": "Iristyle@github" + }, + { + "name": "Marcello Nuccio", + "email": "marcello.nuccio@gmail.com" + }, + { + "name": "pavelgj", + "email": "pavelgj@gmail.com" + }, + { + "name": "Bulat Shakirzyanov", + "email": "mallluhuct@gmail.com" + }, + { + "name": "Ethan J. Brown", + "email": "ethan_j_brown@hotmail.com" + }, + { + "name": "Hugues Malphettes", + "email": "hmalphettes@gmail.com" + }, + { + "name": "Igor Minar", + "email": "iiminar@gmail.com" + }, + { + "name": "James Ford", + "email": "jford@psyked.co.uk" + }, + { + "name": "Roarke Gaskill", + "email": "roarke.gaskill@gmail.com" + }, + { + "name": "ngiebel", + "email": "ngiebel@starkinvestments.com" + }, + { + "name": "rdodev", + "email": "rubenoz@gmail.com" + }, + { + "name": "Alexander Shtuchkin", + "email": "ashtuchkin@gmail.com" + }, + { + "name": "Andy Joslin", + "email": "andytjoslin@gmail.com" + }, + { + "name": "AvnerCohen", + "email": "israbirding@gmail.com" + }, + { + "name": "Breno Calazans", + "email": "breno@vtex.com.br" + }, + { + "name": "Brian Ford", + "email": "btford@umich.edu" + }, + { + "name": "Chad Smith", + "email": "chad@configit.com" + }, + { + "name": "Chris Dawson", + "email": "xrdawson@gmail.com" + }, + { + "name": "Danny Croft", + "email": "danny.croft@yahoo.co.uk" + }, + { + "name": "David Jensen", + "email": "david@frode.(none)", + "url": "none" + }, + { + "name": "David M. Karr", + "email": "dk068x@att.com" + }, + { + "name": "David Souther", + "email": "davidsouther@gmail.com" + }, + { + "name": "Dillon", + "email": "mdillon@reachmail.com" + }, + { + "name": "Ed Rooth", + "email": "ed.rooth@rackspace.com" + }, + { + "name": "Eldar Jafarov", + "email": "djkojb@gmail.com" + }, + { + "name": "Eric Baer", + "email": "me@ericbaer.com" + }, + { + "name": "Franck Garcia", + "email": "garcia.franck@gmail.com" + }, + { + "name": "Fred Sauer", + "email": "fredsa@google.com" + }, + { + "name": "Geert Van Laethem", + "email": "geert.van.laethem@pandora.be" + }, + { + "name": "Igor Minar", + "email": "igor@angularjs.org" + }, + { + "name": "James Shore", + "email": "jshore@jamesshore.com" + }, + { + "name": "Jeff Froom", + "email": "jeff@jfroom.com" + }, + { + "name": "Jeff Jewiss", + "email": "jeffjewiss@gmail.com" + }, + { + "name": "Julian Connor", + "email": "julian.connor@venmo.com" + }, + { + "name": "Karolis Narkevicius", + "email": "karolis.n@gmail.com" + }, + { + "name": "Kevin Ortman", + "email": "kevin_ortman@msn.com" + }, + { + "name": "Lukasz Zatorski", + "email": "lzatorski@gmail.com" + }, + { + "name": "Marko Anastasov", + "email": "marko@renderedtext.com" + }, + { + "name": "Martin Lemanski", + "email": "martin.lemanski@gmx.at" + }, + { + "name": "Matias Niemelä", + "email": "matias@yearofmoo.com" + }, + { + "name": "Merrick Christensen", + "email": "merrick.christensen@gmail.com" + }, + { + "name": "Milan Aleksic", + "email": "milanaleksic@gmail.com" + }, + { + "name": "Nick Payne", + "email": "nick@kurai.co.uk" + }, + { + "name": "Nish", + "email": "nishantpatel611@gmail.com" + }, + { + "name": "Nuno Job", + "email": "nunojobpinto@gmail.com" + }, + { + "name": "Pascal Hartig", + "email": "phartig@rdrei.net" + }, + { + "name": "Patrick Lussan", + "email": "patrick.lussan@componize.com" + }, + { + "name": "Patrik Henningsson", + "email": "patrik.henningsson@gmail.com" + }, + { + "name": "Pete Bacon Darwin", + "email": "pete@bacondarwin.com" + }, + { + "name": "Pete Swan", + "email": "pete@indabamusic.com" + }, + { + "name": "Peter Yates", + "email": "pd.yates@gmail.com" + }, + { + "name": "Remy Sharp", + "email": "remy@remysharp.com" + }, + { + "name": "Shane Osbourne", + "email": "shane.osbourne8@gmail.com" + }, + { + "name": "Tim Olshansky", + "email": "tim.olshansky@gmail.com" + }, + { + "name": "Veronica Lynn", + "email": "veronica.lynn@redjack.com" + }, + { + "name": "Yi Wang", + "email": "e@yi-wang.me" + }, + { + "name": "Zhang zhengzheng", + "email": "code@tychio.net" + }, + { + "name": "ahaurw01", + "email": "ahaurwitz@gmail.com" + }, + { + "name": "ashaffer", + "email": "darawk@gmail.com" + }, + { + "name": "hrgdavor", + "email": "hrgdavor@gmail.com" + }, + { + "name": "lanshunfang", + "email": "lanshunfang@gmail.com" + }, + { + "name": "toran billups", + "email": "toranb@gmail.com" + } + ], + "dependencies": { + "di": "~0.0.1", + "socket.io": "~0.9.13", + "chokidar": "~0.7.0", + "glob": "~3.1.21", + "minimatch": "~0.2", + "http-proxy": "~0.10", + "optimist": "~0.3", + "coffee-script": "~1.6", + "rimraf": "~2.1", + "q": "~0.9", + "colors": "0.6.0-1", + "lodash": "~1.1", + "mime": "~1.2", + "log4js": "~0.6.3", + "useragent": "~2.0.4", + "graceful-fs": "~1.2.1", + "connect": "~2.8.4" + }, + "peerDependencies": { + "karma-jasmine": "*", + "karma-requirejs": "*", + "karma-coffee-preprocessor": "*", + "karma-html2js-preprocessor": "*", + "karma-chrome-launcher": "*", + "karma-firefox-launcher": "*", + "karma-phantomjs-launcher": "*", + "karma-script-launcher": "*" + }, + "devDependencies": { + "grunt": "~0.4", + "grunt-simple-mocha": "git://github.com/yaymukund/grunt-simple-mocha.git", + "grunt-contrib-jshint": "~0.3", + "grunt-coffeelint": "~0.0.6", + "grunt-npm": "~0.0.1", + "grunt-bump": "~0.0.10", + "grunt-conventional-changelog": "~1.0.0", + "grunt-auto-release": "~0.0.3", + "mocks": "~0.0.10", + "which": "~1.0", + "sinon-chai": "~2.3", + "chai": "~1.5", + "mocha": "~1.8", + "sinon": "~1.6", + "timer-shim": "~0.2", + "chai-as-promised": "~3.2", + "qq": "~0.3", + "karma-jasmine": "*", + "karma-mocha": "*", + "karma-qunit": "*", + "karma-coverage": "*", + "karma-requirejs": "*", + "karma-growl-reporter": "*", + "karma-junit-reporter": "*", + "karma-chrome-launcher": "*", + "karma-firefox-launcher": "*", + "karma-sauce-launcher": "*", + "karma-phantomjs-launcher": "*", + "karma-ng-scenario": "*", + "karma-coffee-preprocessor": "*", + "karma-html2js-preprocessor": "*", + "karma-browserstack-launcher": "git://github.com/karma-runner/karma-browserstack-launcher.git", + "semver": "~1.1.4", + "grunt-contrib-watch": "~0.5.0" + }, + "main": "./lib/index", + "bin": { + "karma": "./bin/karma" + }, + "engines": { + "node": "~0.8 || ~0.10" + }, + "version": "0.10.6", + "readme": "# Karma [![Build Status](https://secure.travis-ci.org/karma-runner/karma.png?branch=master)](http://travis-ci.org/karma-runner/karma)\n\nA simple tool that allows you to execute JavaScript code in multiple\n_real_ browsers, powered by [Node.js] and [Socket.io].\n\n> The main purpose of Karma is to make your TDD development easy,\n> fast, and fun.\n\n## When should I use Karma?\n\n* You want to test code in *real* browsers.\n* You want to test code in multiple browsers (desktop, mobile,\n tablets, etc.).\n* You want to execute your tests locally during development.\n* You want to execute your tests on a continuous integration server.\n* You want to execute your tests on every save.\n* You love your terminal.\n* You don't want your (testing) life to suck.\n* You want to use [Istanbul] to automagically generate coverage\n reports.\n* You want to use [RequireJS] for your source files.\n\n\n## But I still want to use \\_insert testing library\\_\n\nKarma is not a testing framework, neither an assertion library,\nso for that you can use pretty much anything you like. Right now out\nof the box there is support for\n\n* [Mocha]\n* [Jasmine]\n* [QUnit]\n* \\_anything else\\_ Write your own adapter. It's not that hard. And we\n are here to help.\n\n\n## Which Browsers can I use?\n\nAll the major browsers are supported, if you want to know more see the\n[Browsers] page.\n\n\n## I want to use it. Where do I sign?\n\nYou don't need to sign anything but here are some resources to help\nyou to get started. And if you need even more infos have a look at our\ngreat [website].\n\n### Obligatory Screencast.\n\nEvery serious project has a screencast, so here is ours. Just click\n[here] and let the show begin.\n\n### NPM Installation.\n\nIf you have [Node.js] installed, it's as simple as\n\n```bash\n$ npm install -g karma\n```\n\nThis will give you the latest stable version available on npm. If you\nwant to live life on the edge you can do so by\n\n```bash\n$ npm install -g karma@canary\n```\n\nThe curious can have a look at the documentation articles for\n[Getting Started] and [Versioning].\n\n### Using it.\n\nGo into your project and create a Karma configuration. That is\njust a simple JavaScript or CoffeeScript file that tells Karma\nwhere all the awesomeness of your project are.\n\nYou can find a simple example in\n[test/client/karma.conf.js](https://github.com/karma-runner/karma/blob/master/test/client/karma.conf.js)\nwhich contains most of the options.\n\nTo create your own from scratch there is the `init` command, which\nwill be named `karma.conf.js` by default:\n\n```bash\n$ karma init\n```\nThis will ask you many questions and if you answered them all correct\nyou will be allowed to use Karma.\n\nFor more information on the configuration options see\n[Configuration File Overview].\n\nNow that you have your configuration all that is left to do is to\nstart Karma:\n```bash\n$ karma start\n```\n\nIf you want to run tests manually (without auto watching file changes), you can:\n```bash\n$ karma run\n```\nBut only if you have started the Karma server before.\n\n\n## Why did you create this?\n\nThroughout the development of [AngularJS], we've been using [JSTD] for\ntesting. I really think that JSTD is a great idea. Unfortunately, we\nhad many problems with JSTD, so we decided to write our own test\nrunner based on the same idea. We wanted a simple tool just for\nexecuting JavaScript tests that is both stable and fast. That's why we\nuse the awesome [Socket.io] library and [Node.js].\n\n\n## I still don't get it. Where can I get help?\n\n* [Docs]\n* [Mailing List]\n* [Issuetracker]\n* [@JsKarma] on Twitter\n\n## This is so great. I want to help.\n\nSee\n[Contributing.md](https://github.com/karma-runner/karma/blob/master/CONTRIBUTING.md)\nor the [docs] for more information.\n\n\n## My boss wants a license. So where is it?\n\n### The MIT License\n\n> Copyright (C) 2011-2013 Vojta Jína.\n>\n> Permission is hereby granted, free of charge, to any person\n> obtaining a copy of this software and associated documentation files\n> (the \"Software\"), to deal in the Software without restriction,\n> including without limitation the rights to use, copy, modify, merge,\n> publish, distribute, sublicense, and/or sell copies of the Software,\n> and to permit persons to whom the Software is furnished to do so,\n> subject to the following conditions:\n>\n> The above copyright notice and this permission notice shall be\n> included in all copies or substantial portions of the Software.\n>\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n> BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n> ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n> CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n> SOFTWARE.\n\n\n\n[AngularJS]: http://angularjs.org/\n[JSTD]: http://code.google.com/p/js-test-driver/\n[Socket.io]: http://socket.io/\n[Node.js]: http://nodejs.org/\n[Jasmine]: http://pivotal.github.io/jasmine/\n[Mocha]: http://visionmedia.github.io/mocha/\n[QUnit]: http://qunitjs.com/\n[here]: http://www.youtube.com/watch?v=MVw8N3hTfCI\n[Mailing List]: https://groups.google.com/forum/#!forum/karma-users\n[Issuetracker]: https://github.com/karma-runner/karma/issues\n[@JsKarma]: http://twitter.com/JsKarma\n[RequireJS]: http://requirejs.org/\n[Istanbul]: https://github.com/gotwarlost/istanbul\n\n[Browsers]: http://karma-runner.github.io/0.8/config/browsers.html\n[Versioning]: http://karma-runner.github.io/0.8/about/versioning.html\n[Configuration File Overview]: http://karma-runner.github.io/0.8/config/configuration-file.html\n[docs]: http://karma-runner.github.io\n[Docs]: http://karma-runner.github.io\n[website]: http://karma-runner.github.io\n", + "readmeFilename": "README.md", + "_id": "karma@0.10.6", + "_from": "karma@>=0.9" +} diff --git a/node_modules/karma/static/client.html b/node_modules/karma/static/client.html new file mode 100644 index 00000000..5a139223 --- /dev/null +++ b/node_modules/karma/static/client.html @@ -0,0 +1,115 @@ + + + + + Karma + + + + + + + + +
    + + + + + + + diff --git a/node_modules/karma/static/context.html b/node_modules/karma/static/context.html new file mode 100644 index 00000000..a1d6cb9e --- /dev/null +++ b/node_modules/karma/static/context.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + %SCRIPTS% + + + diff --git a/node_modules/karma/static/debug.html b/node_modules/karma/static/debug.html new file mode 100644 index 00000000..772c1fd9 --- /dev/null +++ b/node_modules/karma/static/debug.html @@ -0,0 +1,48 @@ + + + + + Karma DEBUG RUNNER + + + + + + + + + %SCRIPTS% + + + diff --git a/node_modules/karma/static/karma.js b/node_modules/karma/static/karma.js new file mode 100644 index 00000000..d23a1e4f --- /dev/null +++ b/node_modules/karma/static/karma.js @@ -0,0 +1,294 @@ +(function(window, document, io) { + +var CONTEXT_URL = 'context.html'; +var VERSION = '%KARMA_VERSION%'; +var KARMA_URL_ROOT = '%KARMA_URL_ROOT%'; + +// connect socket.io +// https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO +var socket = io.connect('http://' + location.host, { + 'reconnection delay': 500, + 'reconnection limit': 2000, + 'resource': KARMA_URL_ROOT.substr(1) + 'socket.io', + 'sync disconnect on unload': true, + 'max reconnection attempts': Infinity +}); + +var browsersElement = document.getElementById('browsers'); +socket.on('info', function(browsers) { + var items = [], status; + for (var i = 0; i < browsers.length; i++) { + status = browsers[i].isReady ? 'idle' : 'executing'; + items.push('
  • ' + browsers[i].name + ' is ' + status + '
  • '); + } + browsersElement.innerHTML = items.join('\n'); +}); +socket.on('disconnect', function() { + browsersElement.innerHTML = ''; +}); + +var titleElement = document.getElementById('title'); +var bannerElement = document.getElementById('banner'); +var updateStatus = function(status) { + return function(param) { + var paramStatus = param ? status.replace('$', param) : status; + titleElement.innerHTML = 'Karma v' + VERSION + ' - ' + paramStatus; + bannerElement.className = status === 'connected' ? 'online' : 'offline'; + }; +}; + +socket.on('connect', updateStatus('connected')); +socket.on('disconnect', updateStatus('disconnected')); +socket.on('reconnecting', updateStatus('reconnecting in $ ms...')); +socket.on('reconnect', updateStatus('re-connected')); +socket.on('reconnect_failed', updateStatus('failed to reconnect')); + +var instanceOf = function(value, constructorName) { + return Object.prototype.toString.apply(value) === '[object ' + constructorName + ']'; +}; + +/* jshint unused: false */ +var Karma = function(socket, context, navigator, location) { + var hasError = false; + var store = {}; + var self = this; + + var resultsBufferLimit = 1; + var resultsBuffer = []; + + this.VERSION = VERSION; + this.config = {}; + + this.setupContext = function(contextWindow) { + if (hasError) { + return; + } + + var getConsole = function(currentWindow) { + return currentWindow.console || { + log: function() {}, + info: function() {}, + warn: function() {}, + error: function() {}, + debug: function() {} + }; + }; + + contextWindow.__karma__ = this; + + // This causes memory leak in Chrome (17.0.963.66) + contextWindow.onerror = function() { + return contextWindow.__karma__.error.apply(contextWindow.__karma__, arguments); + }; + + contextWindow.onbeforeunload = function(e, b) { + if (context.src !== 'about:blank') { + // TODO(vojta): show what test (with explanation about jasmine.UPDATE_INTERVAL) + contextWindow.__karma__.error('Some of your tests did a full page reload!'); + } + }; + + // patch the console + var localConsole = contextWindow.console = getConsole(contextWindow); + var browserConsoleLog = localConsole.log; + var logMethods = ['log', 'info', 'warn', 'error', 'debug']; + var patchConsoleMethod = function(method) { + var orig = localConsole[method]; + if (!orig) { + return; + } + localConsole[method] = function() { + self.log(method, arguments); + return Function.prototype.apply.call(orig, localConsole, arguments); + }; + }; + for (var i = 0; i < logMethods.length; i++) { + patchConsoleMethod(logMethods[i]); + } + + contextWindow.dump = function() { + self.log('dump', arguments); + }; + + contextWindow.alert = function(msg) { + self.log('alert', [msg]); + }; + }; + + this.log = function(type, args) { + var values = []; + + for (var i = 0; i < args.length; i++) { + values.push(this.stringify(args[i], 3)); + } + + this.info({log: values.join(', '), type: type}); + }; + + this.stringify = function(obj, depth) { + + if (depth === 0) { + return '...'; + } + + if (obj === null) { + return 'null'; + } + + switch (typeof obj) { + case 'string': + return '\'' + obj + '\''; + case 'undefined': + return 'undefined'; + case 'function': + return obj.toString().replace(/\{[\s\S]*\}/, '{ ... }'); + case 'boolean': + return obj ? 'true' : 'false'; + case 'object': + var strs = []; + if (instanceOf(obj, 'Array')) { + strs.push('['); + for (var i = 0, ii = obj.length; i < ii; i++) { + if (i) { + strs.push(', '); + } + strs.push(this.stringify(obj[i], depth - 1)); + } + strs.push(']'); + } else if (instanceOf(obj, 'Date')) { + return obj.toString(); + } else if (instanceOf(obj, 'Text')) { + return obj.nodeValue; + } else if (instanceOf(obj, 'Comment')) { + return ''; + } else if (obj.outerHTML) { + return obj.outerHTML; + } else { + strs.push(obj.constructor.name); + strs.push('{'); + var first = true; + for(var key in obj) { + if (obj.hasOwnProperty(key)) { + if (first) { first = false; } else { strs.push(', '); } + strs.push(key + ': ' + this.stringify(obj[key], depth - 1)); + } + } + strs.push('}'); + } + return strs.join(''); + default: + return obj; + } + }; + + + var clearContext = function() { + context.src = 'about:blank'; + }; + + // error during js file loading (most likely syntax error) + // we are not going to execute at all + this.error = function(msg, url, line) { + hasError = true; + socket.emit('error', url ? msg + '\nat ' + url + (line ? ':' + line : '') : msg); + this.complete(); + return false; + }; + + this.result = function(result) { + if (resultsBufferLimit === 1) { + return socket.emit('result', result); + } + + resultsBuffer.push(result); + + if (resultsBuffer.length === resultsBufferLimit) { + socket.emit('result', resultsBuffer); + resultsBuffer = []; + } + }; + + this.complete = function(result) { + if (resultsBuffer.length) { + socket.emit('result', resultsBuffer); + resultsBuffer = []; + } + + // give the browser some time to breath, there could be a page reload, but because a bunch of + // tests could run in the same event loop, we wouldn't notice. + setTimeout(function() { + socket.emit('complete', result || {}); + clearContext(); + }, 0); + }; + + this.info = function(info) { + socket.emit('info', info); + }; + + // all files loaded, let's start the execution + this.loaded = function() { + // has error -> cancel + if (!hasError) { + this.start(this.config); + } + + // remove reference to child iframe + this.start = null; + }; + + this.store = function(key, value) { + if (typeof value === 'undefined') { + return store[key]; + } + + if (Object.prototype.toString.apply(value) === '[object Array]') { + var s = store[key] = []; + for (var i = 0; i < value.length; i++) { + s.push(value[i]); + } + } else { + // TODO(vojta): clone objects + deep + store[key] = value; + } + }; + + // supposed to be overriden by the context + // TODO(vojta): support multiple callbacks (queue) + this.start = this.complete; + + socket.on('execute', function(cfg) { + // reset hasError and reload the iframe + hasError = false; + self.config = cfg; + context.src = CONTEXT_URL; + + // clear the console before run + // works only on FF (Safari, Chrome do not allow to clear console from js source) + if (window.console && window.console.clear) { + window.console.clear(); + } + }); + + // report browser name, id + socket.on('connect', function() { + var transport = socket.socket.transport.name; + + // TODO(vojta): make resultsBufferLimit configurable + if (transport === 'websocket' || transport === 'flashsocket') { + resultsBufferLimit = 1; + } else { + resultsBufferLimit = 50; + } + + socket.emit('register', { + name: navigator.userAgent, + id: parseInt((location.search.match(/\?id=(.*)/) || [])[1], 10) || null + }); + }); +}; + + +window.karma = new Karma(socket, document.getElementById('context'), window.navigator, window.location); + +})(window, document, window.io); diff --git a/node_modules/karma/test-results.xml b/node_modules/karma/test-results.xml new file mode 100644 index 00000000..e9d7c52f --- /dev/null +++ b/node_modules/karma/test-results.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/node_modules/karma/thesis.pdf b/node_modules/karma/thesis.pdf new file mode 100644 index 00000000..76cf7cc8 Binary files /dev/null and b/node_modules/karma/thesis.pdf differ diff --git a/node_modules/requirejs/README.md b/node_modules/requirejs/README.md new file mode 100644 index 00000000..545b31d7 --- /dev/null +++ b/node_modules/requirejs/README.md @@ -0,0 +1,9 @@ +# requirejs + +RequireJS for use in Node. includes: + +* r.js: the RequireJS optimizer, and AMD runtime for use in Node. +* require.js: The browser-based AMD loader. + +More information at http://requirejs.org + diff --git a/node_modules/requirejs/bin/r.js b/node_modules/requirejs/bin/r.js new file mode 100755 index 00000000..55028dad --- /dev/null +++ b/node_modules/requirejs/bin/r.js @@ -0,0 +1,26059 @@ +#!/usr/bin/env node +/** + * @license r.js 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/* + * This is a bootstrap script to allow running RequireJS in the command line + * in either a Java/Rhino or Node environment. It is modified by the top-level + * dist.js file to inject other files to completely enable this file. It is + * the shell of the r.js file. + */ + +/*jslint evil: true, nomen: true, sloppy: true */ +/*global readFile: true, process: false, Packages: false, print: false, +console: false, java: false, module: false, requirejsVars, navigator, +document, importScripts, self, location, Components, FileUtils */ + +var requirejs, require, define, xpcUtil; +(function (console, args, readFileFunc) { + var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, + nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, + version = '2.1.9', + jsSuffixRegExp = /\.js$/, + commandOption = '', + useLibLoaded = {}, + //Used by jslib/rhino/args.js + rhinoArgs = args, + //Used by jslib/xpconnect/args.js + xpconnectArgs = args, + readFile = typeof readFileFunc !== 'undefined' ? readFileFunc : null; + + function showHelp() { + console.log('See https://github.com/jrburke/r.js for usage.'); + } + + if ((typeof navigator !== 'undefined' && typeof document !== 'undefined') || + (typeof importScripts !== 'undefined' && typeof self !== 'undefined')) { + env = 'browser'; + + readFile = function (path) { + return fs.readFileSync(path, 'utf8'); + }; + + exec = function (string) { + return eval(string); + }; + + exists = function () { + console.log('x.js exists not applicable in browser env'); + return false; + }; + + } else if (typeof Packages !== 'undefined') { + env = 'rhino'; + + fileName = args[0]; + + if (fileName && fileName.indexOf('-') === 0) { + commandOption = fileName.substring(1); + fileName = args[1]; + } + + //Set up execution context. + rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext(); + + exec = function (string, name) { + return rhinoContext.evaluateString(this, string, name, 0, null); + }; + + exists = function (fileName) { + return (new java.io.File(fileName)).exists(); + }; + + //Define a console.log for easier logging. Don't + //get fancy though. + if (typeof console === 'undefined') { + console = { + log: function () { + print.apply(undefined, arguments); + } + }; + } + } else if (typeof process !== 'undefined' && process.versions && !!process.versions.node) { + env = 'node'; + + //Get the fs module via Node's require before it + //gets replaced. Used in require/node.js + fs = require('fs'); + vm = require('vm'); + path = require('path'); + //In Node 0.7+ existsSync is on fs. + existsForNode = fs.existsSync || path.existsSync; + + nodeRequire = require; + nodeDefine = define; + reqMain = require.main; + + //Temporarily hide require and define to allow require.js to define + //them. + require = undefined; + define = undefined; + + readFile = function (path) { + return fs.readFileSync(path, 'utf8'); + }; + + exec = function (string, name) { + return vm.runInThisContext(this.requirejsVars.require.makeNodeWrapper(string), + name ? fs.realpathSync(name) : ''); + }; + + exists = function (fileName) { + return existsForNode(fileName); + }; + + + fileName = process.argv[2]; + + if (fileName && fileName.indexOf('-') === 0) { + commandOption = fileName.substring(1); + fileName = process.argv[3]; + } + } else if (typeof Components !== 'undefined' && Components.classes && Components.interfaces) { + env = 'xpconnect'; + + Components.utils['import']('resource://gre/modules/FileUtils.jsm'); + Cc = Components.classes; + Ci = Components.interfaces; + + fileName = args[0]; + + if (fileName && fileName.indexOf('-') === 0) { + commandOption = fileName.substring(1); + fileName = args[1]; + } + + xpcUtil = { + isWindows: ('@mozilla.org/windows-registry-key;1' in Cc), + cwd: function () { + return FileUtils.getFile("CurWorkD", []).path; + }, + + //Remove . and .. from paths, normalize on front slashes + normalize: function (path) { + //There has to be an easier way to do this. + var i, part, ary, + firstChar = path.charAt(0); + + if (firstChar !== '/' && + firstChar !== '\\' && + path.indexOf(':') === -1) { + //A relative path. Use the current working directory. + path = xpcUtil.cwd() + '/' + path; + } + + ary = path.replace(/\\/g, '/').split('/'); + + for (i = 0; i < ary.length; i += 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + ary.splice(i - 1, 2); + i -= 2; + } + } + return ary.join('/'); + }, + + xpfile: function (path) { + var fullPath; + try { + fullPath = xpcUtil.normalize(path); + if (xpcUtil.isWindows) { + fullPath = fullPath.replace(/\//g, '\\'); + } + return new FileUtils.File(fullPath); + } catch (e) { + throw new Error((fullPath || path) + ' failed: ' + e); + } + }, + + readFile: function (/*String*/path, /*String?*/encoding) { + //A file read function that can deal with BOMs + encoding = encoding || "utf-8"; + + var inStream, convertStream, + readData = {}, + fileObj = xpcUtil.xpfile(path); + + //XPCOM, you so crazy + try { + inStream = Cc['@mozilla.org/network/file-input-stream;1'] + .createInstance(Ci.nsIFileInputStream); + inStream.init(fileObj, 1, 0, false); + + convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] + .createInstance(Ci.nsIConverterInputStream); + convertStream.init(inStream, encoding, inStream.available(), + Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + + convertStream.readString(inStream.available(), readData); + return readData.value; + } catch (e) { + throw new Error((fileObj && fileObj.path || '') + ': ' + e); + } finally { + if (convertStream) { + convertStream.close(); + } + if (inStream) { + inStream.close(); + } + } + } + }; + + readFile = xpcUtil.readFile; + + exec = function (string) { + return eval(string); + }; + + exists = function (fileName) { + return xpcUtil.xpfile(fileName).exists(); + }; + + //Define a console.log for easier logging. Don't + //get fancy though. + if (typeof console === 'undefined') { + console = { + log: function () { + print.apply(undefined, arguments); + } + }; + } + } + + /** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +//Not using strict: uneven strict support in browsers, #392, and causes +//problems with requirejs.exec()/transpiler plugins that may not be strict. +/*jslint regexp: true, nomen: true, sloppy: true */ +/*global window, navigator, document, importScripts, setTimeout, opera */ + + +(function (global) { + var req, s, head, baseElement, dataMain, src, + interactiveScript, currentlyAddingScript, mainScript, subPath, + version = '2.1.9', + commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, + cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, + jsSuffixRegExp = /\.js$/, + currDirRegExp = /^\.\//, + op = Object.prototype, + ostring = op.toString, + hasOwn = op.hasOwnProperty, + ap = Array.prototype, + apsp = ap.splice, + isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document), + isWebWorker = !isBrowser && typeof importScripts !== 'undefined', + //PS3 indicates loaded and complete, but need to wait for complete + //specifically. Sequence is 'loading', 'loaded', execution, + // then 'complete'. The UA check is unfortunate, but not sure how + //to feature test w/o causing perf issues. + readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? + /^complete$/ : /^(complete|loaded)$/, + defContextName = '_', + //Oh the tragedy, detecting opera. See the usage of isOpera for reason. + isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', + contexts = {}, + cfg = {}, + globalDefQueue = [], + useInteractive = false; + + function isFunction(it) { + return ostring.call(it) === '[object Function]'; + } + + function isArray(it) { + return ostring.call(it) === '[object Array]'; + } + + /** + * Helper function for iterating over an array. If the func returns + * a true value, it will break out of the loop. + */ + function each(ary, func) { + if (ary) { + var i; + for (i = 0; i < ary.length; i += 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + /** + * Helper function for iterating over an array backwards. If the func + * returns a true value, it will break out of the loop. + */ + function eachReverse(ary, func) { + if (ary) { + var i; + for (i = ary.length - 1; i > -1; i -= 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + function getOwn(obj, prop) { + return hasProp(obj, prop) && obj[prop]; + } + + /** + * Cycles over properties in an object and calls a function for each + * property value. If the function returns a truthy value, then the + * iteration is stopped. + */ + function eachProp(obj, func) { + var prop; + for (prop in obj) { + if (hasProp(obj, prop)) { + if (func(obj[prop], prop)) { + break; + } + } + } + } + + /** + * Simple function to mix in properties from source into target, + * but only if target does not already have a property of the same name. + */ + function mixin(target, source, force, deepStringMixin) { + if (source) { + eachProp(source, function (value, prop) { + if (force || !hasProp(target, prop)) { + if (deepStringMixin && typeof value !== 'string') { + if (!target[prop]) { + target[prop] = {}; + } + mixin(target[prop], value, force, deepStringMixin); + } else { + target[prop] = value; + } + } + }); + } + return target; + } + + //Similar to Function.prototype.bind, but the 'this' object is specified + //first, since it is easier to read/figure out what 'this' will be. + function bind(obj, fn) { + return function () { + return fn.apply(obj, arguments); + }; + } + + function scripts() { + return document.getElementsByTagName('script'); + } + + function defaultOnError(err) { + throw err; + } + + //Allow getting a global that expressed in + //dot notation, like 'a.b.c'. + function getGlobal(value) { + if (!value) { + return value; + } + var g = global; + each(value.split('.'), function (part) { + g = g[part]; + }); + return g; + } + + /** + * Constructs an error with a pointer to an URL with more information. + * @param {String} id the error ID that maps to an ID on a web page. + * @param {String} message human readable error. + * @param {Error} [err] the original error, if there is one. + * + * @returns {Error} + */ + function makeError(id, msg, err, requireModules) { + var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); + e.requireType = id; + e.requireModules = requireModules; + if (err) { + e.originalError = err; + } + return e; + } + + if (typeof define !== 'undefined') { + //If a define is already in play via another AMD loader, + //do not overwrite. + return; + } + + if (typeof requirejs !== 'undefined') { + if (isFunction(requirejs)) { + //Do not overwrite and existing requirejs instance. + return; + } + cfg = requirejs; + requirejs = undefined; + } + + //Allow for a require config object + if (typeof require !== 'undefined' && !isFunction(require)) { + //assume it is a config object. + cfg = require; + require = undefined; + } + + function newContext(contextName) { + var inCheckLoaded, Module, context, handlers, + checkLoadedTimeoutId, + config = { + //Defaults. Do not set a default for map + //config to speed up normalize(), which + //will run faster if there is no default. + waitSeconds: 7, + baseUrl: './', + paths: {}, + pkgs: {}, + shim: {}, + config: {} + }, + registry = {}, + //registry of just enabled modules, to speed + //cycle breaking code when lots of modules + //are registered, but not activated. + enabledRegistry = {}, + undefEvents = {}, + defQueue = [], + defined = {}, + urlFetched = {}, + requireCounter = 1, + unnormalizedCounter = 1; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; ary[i]; i += 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @param {Boolean} applyMap apply the map config to the value. Should + * only be done if this normalization is for a dependency ID. + * @returns {String} normalized name + */ + function normalize(name, baseName, applyMap) { + var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment, + foundMap, foundI, foundStarMap, starI, + baseParts = baseName && baseName.split('/'), + normalizedBaseParts = baseParts, + map = config.map, + starMap = map && map['*']; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + if (getOwn(config.pkgs, baseName)) { + //If the baseName is a package name, then just treat it as one + //name to concat the name with. + normalizedBaseParts = baseParts = [baseName]; + } else { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + } + + name = normalizedBaseParts.concat(name.split('/')); + trimDots(name); + + //Some use of packages may use a . path to reference the + //'main' module name, so normalize for that. + pkgConfig = getOwn(config.pkgs, (pkgName = name[0])); + name = name.join('/'); + if (pkgConfig && name === pkgName + '/' + pkgConfig.main) { + name = pkgName; + } + } else if (name.indexOf('./') === 0) { + // No baseName, so this is ID is resolved relative + // to baseUrl, pull off the leading dot. + name = name.substring(2); + } + } + + //Apply map config if available. + if (applyMap && map && (baseParts || starMap)) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join('/'); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = getOwn(map, baseParts.slice(0, j).join('/')); + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = getOwn(mapValue, nameSegment); + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) { + foundStarMap = getOwn(starMap, nameSegment); + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function removeScript(name) { + if (isBrowser) { + each(scripts(), function (scriptNode) { + if (scriptNode.getAttribute('data-requiremodule') === name && + scriptNode.getAttribute('data-requirecontext') === context.contextName) { + scriptNode.parentNode.removeChild(scriptNode); + return true; + } + }); + } + } + + function hasPathFallback(id) { + var pathConfig = getOwn(config.paths, id); + if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { + //Pop off the first array value, since it failed, and + //retry + pathConfig.shift(); + context.require.undef(id); + context.require([id]); + return true; + } + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + /** + * Creates a module mapping that includes plugin prefix, module + * name, and path. If parentModuleMap is provided it will + * also normalize the name via require.normalize() + * + * @param {String} name the module name + * @param {String} [parentModuleMap] parent module map + * for the module name, used to resolve relative names. + * @param {Boolean} isNormalized: is the ID already normalized. + * This is true if this call is done for a define() module ID. + * @param {Boolean} applyMap: apply the map config to the ID. + * Should only be true if this map is for a dependency. + * + * @returns {Object} + */ + function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { + var url, pluginModule, suffix, nameParts, + prefix = null, + parentName = parentModuleMap ? parentModuleMap.name : null, + originalName = name, + isDefine = true, + normalizedName = ''; + + //If no name, then it means it is a require call, generate an + //internal name. + if (!name) { + isDefine = false; + name = '_@r' + (requireCounter += 1); + } + + nameParts = splitPrefix(name); + prefix = nameParts[0]; + name = nameParts[1]; + + if (prefix) { + prefix = normalize(prefix, parentName, applyMap); + pluginModule = getOwn(defined, prefix); + } + + //Account for relative paths if there is a base name. + if (name) { + if (prefix) { + if (pluginModule && pluginModule.normalize) { + //Plugin is loaded, use its normalize method. + normalizedName = pluginModule.normalize(name, function (name) { + return normalize(name, parentName, applyMap); + }); + } else { + normalizedName = normalize(name, parentName, applyMap); + } + } else { + //A regular module. + normalizedName = normalize(name, parentName, applyMap); + + //Normalized name may be a plugin ID due to map config + //application in normalize. The map config values must + //already be normalized, so do not need to redo that part. + nameParts = splitPrefix(normalizedName); + prefix = nameParts[0]; + normalizedName = nameParts[1]; + isNormalized = true; + + url = context.nameToUrl(normalizedName); + } + } + + //If the id is a plugin id that cannot be determined if it needs + //normalization, stamp it with a unique ID so two matching relative + //ids that may conflict can be separate. + suffix = prefix && !pluginModule && !isNormalized ? + '_unnormalized' + (unnormalizedCounter += 1) : + ''; + + return { + prefix: prefix, + name: normalizedName, + parentMap: parentModuleMap, + unnormalized: !!suffix, + url: url, + originalName: originalName, + isDefine: isDefine, + id: (prefix ? + prefix + '!' + normalizedName : + normalizedName) + suffix + }; + } + + function getModule(depMap) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (!mod) { + mod = registry[id] = new context.Module(depMap); + } + + return mod; + } + + function on(depMap, name, fn) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (hasProp(defined, id) && + (!mod || mod.defineEmitComplete)) { + if (name === 'defined') { + fn(defined[id]); + } + } else { + mod = getModule(depMap); + if (mod.error && name === 'error') { + fn(mod.error); + } else { + mod.on(name, fn); + } + } + } + + function onError(err, errback) { + var ids = err.requireModules, + notified = false; + + if (errback) { + errback(err); + } else { + each(ids, function (id) { + var mod = getOwn(registry, id); + if (mod) { + //Set error on module, so it skips timeout checks. + mod.error = err; + if (mod.events.error) { + notified = true; + mod.emit('error', err); + } + } + }); + + if (!notified) { + req.onError(err); + } + } + } + + /** + * Internal method to transfer globalQueue items to this context's + * defQueue. + */ + function takeGlobalQueue() { + //Push all the globalDefQueue items into the context's defQueue + if (globalDefQueue.length) { + //Array splice in the values since the context code has a + //local var ref to defQueue, so cannot just reassign the one + //on context. + apsp.apply(defQueue, + [defQueue.length - 1, 0].concat(globalDefQueue)); + globalDefQueue = []; + } + } + + handlers = { + 'require': function (mod) { + if (mod.require) { + return mod.require; + } else { + return (mod.require = context.makeRequire(mod.map)); + } + }, + 'exports': function (mod) { + mod.usingExports = true; + if (mod.map.isDefine) { + if (mod.exports) { + return mod.exports; + } else { + return (mod.exports = defined[mod.map.id] = {}); + } + } + }, + 'module': function (mod) { + if (mod.module) { + return mod.module; + } else { + return (mod.module = { + id: mod.map.id, + uri: mod.map.url, + config: function () { + var c, + pkg = getOwn(config.pkgs, mod.map.id); + // For packages, only support config targeted + // at the main module. + c = pkg ? getOwn(config.config, mod.map.id + '/' + pkg.main) : + getOwn(config.config, mod.map.id); + return c || {}; + }, + exports: defined[mod.map.id] + }); + } + } + }; + + function cleanRegistry(id) { + //Clean up machinery used for waiting modules. + delete registry[id]; + delete enabledRegistry[id]; + } + + function breakCycle(mod, traced, processed) { + var id = mod.map.id; + + if (mod.error) { + mod.emit('error', mod.error); + } else { + traced[id] = true; + each(mod.depMaps, function (depMap, i) { + var depId = depMap.id, + dep = getOwn(registry, depId); + + //Only force things that have not completed + //being defined, so still in the registry, + //and only if it has not been matched up + //in the module already. + if (dep && !mod.depMatched[i] && !processed[depId]) { + if (getOwn(traced, depId)) { + mod.defineDep(i, defined[depId]); + mod.check(); //pass false? + } else { + breakCycle(dep, traced, processed); + } + } + }); + processed[id] = true; + } + } + + function checkLoaded() { + var map, modId, err, usingPathFallback, + waitInterval = config.waitSeconds * 1000, + //It is possible to disable the wait interval by using waitSeconds of 0. + expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), + noLoads = [], + reqCalls = [], + stillLoading = false, + needCycleCheck = true; + + //Do not bother if this call was a result of a cycle break. + if (inCheckLoaded) { + return; + } + + inCheckLoaded = true; + + //Figure out the state of all the modules. + eachProp(enabledRegistry, function (mod) { + map = mod.map; + modId = map.id; + + //Skip things that are not enabled or in error state. + if (!mod.enabled) { + return; + } + + if (!map.isDefine) { + reqCalls.push(mod); + } + + if (!mod.error) { + //If the module should be executed, and it has not + //been inited and time is up, remember it. + if (!mod.inited && expired) { + if (hasPathFallback(modId)) { + usingPathFallback = true; + stillLoading = true; + } else { + noLoads.push(modId); + removeScript(modId); + } + } else if (!mod.inited && mod.fetched && map.isDefine) { + stillLoading = true; + if (!map.prefix) { + //No reason to keep looking for unfinished + //loading. If the only stillLoading is a + //plugin resource though, keep going, + //because it may be that a plugin resource + //is waiting on a non-plugin cycle. + return (needCycleCheck = false); + } + } + } + }); + + if (expired && noLoads.length) { + //If wait time expired, throw error of unloaded modules. + err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads); + err.contextName = context.contextName; + return onError(err); + } + + //Not expired, check for a cycle. + if (needCycleCheck) { + each(reqCalls, function (mod) { + breakCycle(mod, {}, {}); + }); + } + + //If still waiting on loads, and the waiting load is something + //other than a plugin resource, or there are still outstanding + //scripts, then just try back later. + if ((!expired || usingPathFallback) && stillLoading) { + //Something is still waiting to load. Wait for it, but only + //if a timeout is not already in effect. + if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { + checkLoadedTimeoutId = setTimeout(function () { + checkLoadedTimeoutId = 0; + checkLoaded(); + }, 50); + } + } + + inCheckLoaded = false; + } + + Module = function (map) { + this.events = getOwn(undefEvents, map.id) || {}; + this.map = map; + this.shim = getOwn(config.shim, map.id); + this.depExports = []; + this.depMaps = []; + this.depMatched = []; + this.pluginMaps = {}; + this.depCount = 0; + + /* this.exports this.factory + this.depMaps = [], + this.enabled, this.fetched + */ + }; + + Module.prototype = { + init: function (depMaps, factory, errback, options) { + options = options || {}; + + //Do not do more inits if already done. Can happen if there + //are multiple define calls for the same module. That is not + //a normal, common case, but it is also not unexpected. + if (this.inited) { + return; + } + + this.factory = factory; + + if (errback) { + //Register for errors on this module. + this.on('error', errback); + } else if (this.events.error) { + //If no errback already, but there are error listeners + //on this module, set up an errback to pass to the deps. + errback = bind(this, function (err) { + this.emit('error', err); + }); + } + + //Do a copy of the dependency array, so that + //source inputs are not modified. For example + //"shim" deps are passed in here directly, and + //doing a direct modification of the depMaps array + //would affect that config. + this.depMaps = depMaps && depMaps.slice(0); + + this.errback = errback; + + //Indicate this module has be initialized + this.inited = true; + + this.ignore = options.ignore; + + //Could have option to init this module in enabled mode, + //or could have been previously marked as enabled. However, + //the dependencies are not known until init is called. So + //if enabled previously, now trigger dependencies as enabled. + if (options.enabled || this.enabled) { + //Enable this module and dependencies. + //Will call this.check() + this.enable(); + } else { + this.check(); + } + }, + + defineDep: function (i, depExports) { + //Because of cycles, defined callback for a given + //export can be called more than once. + if (!this.depMatched[i]) { + this.depMatched[i] = true; + this.depCount -= 1; + this.depExports[i] = depExports; + } + }, + + fetch: function () { + if (this.fetched) { + return; + } + this.fetched = true; + + context.startTime = (new Date()).getTime(); + + var map = this.map; + + //If the manager is for a plugin managed resource, + //ask the plugin to load it now. + if (this.shim) { + context.makeRequire(this.map, { + enableBuildCallback: true + })(this.shim.deps || [], bind(this, function () { + return map.prefix ? this.callPlugin() : this.load(); + })); + } else { + //Regular dependency. + return map.prefix ? this.callPlugin() : this.load(); + } + }, + + load: function () { + var url = this.map.url; + + //Regular dependency. + if (!urlFetched[url]) { + urlFetched[url] = true; + context.load(this.map.id, url); + } + }, + + /** + * Checks if the module is ready to define itself, and if so, + * define it. + */ + check: function () { + if (!this.enabled || this.enabling) { + return; + } + + var err, cjsModule, + id = this.map.id, + depExports = this.depExports, + exports = this.exports, + factory = this.factory; + + if (!this.inited) { + this.fetch(); + } else if (this.error) { + this.emit('error', this.error); + } else if (!this.defining) { + //The factory could trigger another require call + //that would result in checking this module to + //define itself again. If already in the process + //of doing that, skip this work. + this.defining = true; + + if (this.depCount < 1 && !this.defined) { + if (isFunction(factory)) { + //If there is an error listener, favor passing + //to that instead of throwing an error. However, + //only do it for define()'d modules. require + //errbacks should not be called for failures in + //their callbacks (#699). However if a global + //onError is set, use that. + if ((this.events.error && this.map.isDefine) || + req.onError !== defaultOnError) { + try { + exports = context.execCb(id, factory, depExports, exports); + } catch (e) { + err = e; + } + } else { + exports = context.execCb(id, factory, depExports, exports); + } + + if (this.map.isDefine) { + //If setting exports via 'module' is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + cjsModule = this.module; + if (cjsModule && + cjsModule.exports !== undefined && + //Make sure it is not already the exports value + cjsModule.exports !== this.exports) { + exports = cjsModule.exports; + } else if (exports === undefined && this.usingExports) { + //exports already set the defined value. + exports = this.exports; + } + } + + if (err) { + err.requireMap = this.map; + err.requireModules = this.map.isDefine ? [this.map.id] : null; + err.requireType = this.map.isDefine ? 'define' : 'require'; + return onError((this.error = err)); + } + + } else { + //Just a literal value + exports = factory; + } + + this.exports = exports; + + if (this.map.isDefine && !this.ignore) { + defined[id] = exports; + + if (req.onResourceLoad) { + req.onResourceLoad(context, this.map, this.depMaps); + } + } + + //Clean up + cleanRegistry(id); + + this.defined = true; + } + + //Finished the define stage. Allow calling check again + //to allow define notifications below in the case of a + //cycle. + this.defining = false; + + if (this.defined && !this.defineEmitted) { + this.defineEmitted = true; + this.emit('defined', this.exports); + this.defineEmitComplete = true; + } + + } + }, + + callPlugin: function () { + var map = this.map, + id = map.id, + //Map already normalized the prefix. + pluginMap = makeModuleMap(map.prefix); + + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(pluginMap); + + on(pluginMap, 'defined', bind(this, function (plugin) { + var load, normalizedMap, normalizedMod, + name = this.map.name, + parentName = this.map.parentMap ? this.map.parentMap.name : null, + localRequire = context.makeRequire(map.parentMap, { + enableBuildCallback: true + }); + + //If current map is not normalized, wait for that + //normalized name to load instead of continuing. + if (this.map.unnormalized) { + //Normalize the ID if the plugin allows it. + if (plugin.normalize) { + name = plugin.normalize(name, function (name) { + return normalize(name, parentName, true); + }) || ''; + } + + //prefix and name should already be normalized, no need + //for applying map config again either. + normalizedMap = makeModuleMap(map.prefix + '!' + name, + this.map.parentMap); + on(normalizedMap, + 'defined', bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true, + ignore: true + }); + })); + + normalizedMod = getOwn(registry, normalizedMap.id); + if (normalizedMod) { + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(normalizedMap); + + if (this.events.error) { + normalizedMod.on('error', bind(this, function (err) { + this.emit('error', err); + })); + } + normalizedMod.enable(); + } + + return; + } + + load = bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true + }); + }); + + load.error = bind(this, function (err) { + this.inited = true; + this.error = err; + err.requireModules = [id]; + + //Remove temp unnormalized modules for this module, + //since they will never be resolved otherwise now. + eachProp(registry, function (mod) { + if (mod.map.id.indexOf(id + '_unnormalized') === 0) { + cleanRegistry(mod.map.id); + } + }); + + onError(err); + }); + + //Allow plugins to load other code without having to know the + //context or how to 'complete' the load. + load.fromText = bind(this, function (text, textAlt) { + /*jslint evil: true */ + var moduleName = map.name, + moduleMap = makeModuleMap(moduleName), + hasInteractive = useInteractive; + + //As of 2.1.0, support just passing the text, to reinforce + //fromText only being called once per resource. Still + //support old style of passing moduleName but discard + //that moduleName in favor of the internal ref. + if (textAlt) { + text = textAlt; + } + + //Turn off interactive script matching for IE for any define + //calls in the text, then turn it back on at the end. + if (hasInteractive) { + useInteractive = false; + } + + //Prime the system by creating a module instance for + //it. + getModule(moduleMap); + + //Transfer any config to this other module. + if (hasProp(config.config, id)) { + config.config[moduleName] = config.config[id]; + } + + try { + req.exec(text); + } catch (e) { + return onError(makeError('fromtexteval', + 'fromText eval for ' + id + + ' failed: ' + e, + e, + [id])); + } + + if (hasInteractive) { + useInteractive = true; + } + + //Mark this as a dependency for the plugin + //resource + this.depMaps.push(moduleMap); + + //Support anonymous modules. + context.completeLoad(moduleName); + + //Bind the value of that module to the value for this + //resource ID. + localRequire([moduleName], load); + }); + + //Use parentName here since the plugin's name is not reliable, + //could be some weird string with no path that actually wants to + //reference the parentName's path. + plugin.load(map.name, localRequire, load, config); + })); + + context.enable(pluginMap, this); + this.pluginMaps[pluginMap.id] = pluginMap; + }, + + enable: function () { + enabledRegistry[this.map.id] = this; + this.enabled = true; + + //Set flag mentioning that the module is enabling, + //so that immediate calls to the defined callbacks + //for dependencies do not trigger inadvertent load + //with the depCount still being zero. + this.enabling = true; + + //Enable each dependency + each(this.depMaps, bind(this, function (depMap, i) { + var id, mod, handler; + + if (typeof depMap === 'string') { + //Dependency needs to be converted to a depMap + //and wired up to this module. + depMap = makeModuleMap(depMap, + (this.map.isDefine ? this.map : this.map.parentMap), + false, + !this.skipMap); + this.depMaps[i] = depMap; + + handler = getOwn(handlers, depMap.id); + + if (handler) { + this.depExports[i] = handler(this); + return; + } + + this.depCount += 1; + + on(depMap, 'defined', bind(this, function (depExports) { + this.defineDep(i, depExports); + this.check(); + })); + + if (this.errback) { + on(depMap, 'error', bind(this, this.errback)); + } + } + + id = depMap.id; + mod = registry[id]; + + //Skip special modules like 'require', 'exports', 'module' + //Also, don't call enable if it is already enabled, + //important in circular dependency cases. + if (!hasProp(handlers, id) && mod && !mod.enabled) { + context.enable(depMap, this); + } + })); + + //Enable each plugin that is used in + //a dependency + eachProp(this.pluginMaps, bind(this, function (pluginMap) { + var mod = getOwn(registry, pluginMap.id); + if (mod && !mod.enabled) { + context.enable(pluginMap, this); + } + })); + + this.enabling = false; + + this.check(); + }, + + on: function (name, cb) { + var cbs = this.events[name]; + if (!cbs) { + cbs = this.events[name] = []; + } + cbs.push(cb); + }, + + emit: function (name, evt) { + each(this.events[name], function (cb) { + cb(evt); + }); + if (name === 'error') { + //Now that the error handler was triggered, remove + //the listeners, since this broken Module instance + //can stay around for a while in the registry. + delete this.events[name]; + } + } + }; + + function callGetModule(args) { + //Skip modules already defined. + if (!hasProp(defined, args[0])) { + getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); + } + } + + function removeListener(node, func, name, ieName) { + //Favor detachEvent because of IE9 + //issue, see attachEvent/addEventListener comment elsewhere + //in this file. + if (node.detachEvent && !isOpera) { + //Probably IE. If not it will throw an error, which will be + //useful to know. + if (ieName) { + node.detachEvent(ieName, func); + } + } else { + node.removeEventListener(name, func, false); + } + } + + /** + * Given an event from a script node, get the requirejs info from it, + * and then removes the event listeners on the node. + * @param {Event} evt + * @returns {Object} + */ + function getScriptData(evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + var node = evt.currentTarget || evt.srcElement; + + //Remove the listeners once here. + removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange'); + removeListener(node, context.onScriptError, 'error'); + + return { + node: node, + id: node && node.getAttribute('data-requiremodule') + }; + } + + function intakeDefines() { + var args; + + //Any defined modules in the global queue, intake them now. + takeGlobalQueue(); + + //Make sure any remaining defQueue items get properly processed. + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); + } else { + //args are id, deps, factory. Should be normalized by the + //define() function. + callGetModule(args); + } + } + } + + context = { + config: config, + contextName: contextName, + registry: registry, + defined: defined, + urlFetched: urlFetched, + defQueue: defQueue, + Module: Module, + makeModuleMap: makeModuleMap, + nextTick: req.nextTick, + onError: onError, + + /** + * Set a configuration for the context. + * @param {Object} cfg config object to integrate. + */ + configure: function (cfg) { + //Make sure the baseUrl ends in a slash. + if (cfg.baseUrl) { + if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { + cfg.baseUrl += '/'; + } + } + + //Save off the paths and packages since they require special processing, + //they are additive. + var pkgs = config.pkgs, + shim = config.shim, + objs = { + paths: true, + config: true, + map: true + }; + + eachProp(cfg, function (value, prop) { + if (objs[prop]) { + if (prop === 'map') { + if (!config.map) { + config.map = {}; + } + mixin(config[prop], value, true, true); + } else { + mixin(config[prop], value, true); + } + } else { + config[prop] = value; + } + }); + + //Merge shim + if (cfg.shim) { + eachProp(cfg.shim, function (value, id) { + //Normalize the structure + if (isArray(value)) { + value = { + deps: value + }; + } + if ((value.exports || value.init) && !value.exportsFn) { + value.exportsFn = context.makeShimExports(value); + } + shim[id] = value; + }); + config.shim = shim; + } + + //Adjust packages if necessary. + if (cfg.packages) { + each(cfg.packages, function (pkgObj) { + var location; + + pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj; + location = pkgObj.location; + + //Create a brand new object on pkgs, since currentPackages can + //be passed in again, and config.pkgs is the internal transformed + //state for all package configs. + pkgs[pkgObj.name] = { + name: pkgObj.name, + location: location || pkgObj.name, + //Remove leading dot in main, so main paths are normalized, + //and remove any trailing .js, since different package + //envs have different conventions: some use a module name, + //some use a file name. + main: (pkgObj.main || 'main') + .replace(currDirRegExp, '') + .replace(jsSuffixRegExp, '') + }; + }); + + //Done with modifications, assing packages back to context config + config.pkgs = pkgs; + } + + //If there are any "waiting to execute" modules in the registry, + //update the maps for them, since their info, like URLs to load, + //may have changed. + eachProp(registry, function (mod, id) { + //If module already has init called, since it is too + //late to modify them, and ignore unnormalized ones + //since they are transient. + if (!mod.inited && !mod.map.unnormalized) { + mod.map = makeModuleMap(id); + } + }); + + //If a deps array or a config callback is specified, then call + //require with those args. This is useful when require is defined as a + //config object before require.js is loaded. + if (cfg.deps || cfg.callback) { + context.require(cfg.deps || [], cfg.callback); + } + }, + + makeShimExports: function (value) { + function fn() { + var ret; + if (value.init) { + ret = value.init.apply(global, arguments); + } + return ret || (value.exports && getGlobal(value.exports)); + } + return fn; + }, + + makeRequire: function (relMap, options) { + options = options || {}; + + function localRequire(deps, callback, errback) { + var id, map, requireMod; + + if (options.enableBuildCallback && callback && isFunction(callback)) { + callback.__requireJsBuild = true; + } + + if (typeof deps === 'string') { + if (isFunction(callback)) { + //Invalid call + return onError(makeError('requireargs', 'Invalid require call'), errback); + } + + //If require|exports|module are requested, get the + //value for them from the special handlers. Caveat: + //this only works while module is being defined. + if (relMap && hasProp(handlers, deps)) { + return handlers[deps](registry[relMap.id]); + } + + //Synchronous access to one module. If require.get is + //available (as in the Node adapter), prefer that. + if (req.get) { + return req.get(context, deps, relMap, localRequire); + } + + //Normalize module name, if it contains . or .. + map = makeModuleMap(deps, relMap, false, true); + id = map.id; + + if (!hasProp(defined, id)) { + return onError(makeError('notloaded', 'Module name "' + + id + + '" has not been loaded yet for context: ' + + contextName + + (relMap ? '' : '. Use require([])'))); + } + return defined[id]; + } + + //Grab defines waiting in the global queue. + intakeDefines(); + + //Mark all the dependencies as needing to be loaded. + context.nextTick(function () { + //Some defines could have been added since the + //require call, collect them. + intakeDefines(); + + requireMod = getModule(makeModuleMap(null, relMap)); + + //Store if map config should be applied to this require + //call for dependencies. + requireMod.skipMap = options.skipMap; + + requireMod.init(deps, callback, errback, { + enabled: true + }); + + checkLoaded(); + }); + + return localRequire; + } + + mixin(localRequire, { + isBrowser: isBrowser, + + /** + * Converts a module name + .extension into an URL path. + * *Requires* the use of a module name. It does not support using + * plain URLs like nameToUrl. + */ + toUrl: function (moduleNamePlusExt) { + var ext, + index = moduleNamePlusExt.lastIndexOf('.'), + segment = moduleNamePlusExt.split('/')[0], + isRelative = segment === '.' || segment === '..'; + + //Have a file extension alias, and it is not the + //dots from a relative path. + if (index !== -1 && (!isRelative || index > 1)) { + ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); + moduleNamePlusExt = moduleNamePlusExt.substring(0, index); + } + + return context.nameToUrl(normalize(moduleNamePlusExt, + relMap && relMap.id, true), ext, true); + }, + + defined: function (id) { + return hasProp(defined, makeModuleMap(id, relMap, false, true).id); + }, + + specified: function (id) { + id = makeModuleMap(id, relMap, false, true).id; + return hasProp(defined, id) || hasProp(registry, id); + } + }); + + //Only allow undef on top level require calls + if (!relMap) { + localRequire.undef = function (id) { + //Bind any waiting define() calls to this context, + //fix for #408 + takeGlobalQueue(); + + var map = makeModuleMap(id, relMap, true), + mod = getOwn(registry, id); + + removeScript(id); + + delete defined[id]; + delete urlFetched[map.url]; + delete undefEvents[id]; + + if (mod) { + //Hold on to listeners in case the + //module will be attempted to be reloaded + //using a different config. + if (mod.events.defined) { + undefEvents[id] = mod.events; + } + + cleanRegistry(id); + } + }; + } + + return localRequire; + }, + + /** + * Called to enable a module if it is still in the registry + * awaiting enablement. A second arg, parent, the parent module, + * is passed in for context, when this method is overriden by + * the optimizer. Not shown here to keep code compact. + */ + enable: function (depMap) { + var mod = getOwn(registry, depMap.id); + if (mod) { + getModule(depMap).enable(); + } + }, + + /** + * Internal method used by environment adapters to complete a load event. + * A load event could be a script load or just a load pass from a synchronous + * load call. + * @param {String} moduleName the name of the module to potentially complete. + */ + completeLoad: function (moduleName) { + var found, args, mod, + shim = getOwn(config.shim, moduleName) || {}, + shExports = shim.exports; + + takeGlobalQueue(); + + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + args[0] = moduleName; + //If already found an anonymous module and bound it + //to this name, then this is some other anon module + //waiting for its completeLoad to fire. + if (found) { + break; + } + found = true; + } else if (args[0] === moduleName) { + //Found matching define call for this script! + found = true; + } + + callGetModule(args); + } + + //Do this after the cycle of callGetModule in case the result + //of those calls/init calls changes the registry. + mod = getOwn(registry, moduleName); + + if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { + if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { + if (hasPathFallback(moduleName)) { + return; + } else { + return onError(makeError('nodefine', + 'No define call for ' + moduleName, + null, + [moduleName])); + } + } else { + //A script that does not call define(), so just simulate + //the call for it. + callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); + } + } + + checkLoaded(); + }, + + /** + * Converts a module name to a file path. Supports cases where + * moduleName may actually be just an URL. + * Note that it **does not** call normalize on the moduleName, + * it is assumed to have already been normalized. This is an + * internal API, not a public one. Use toUrl for the public API. + */ + nameToUrl: function (moduleName, ext, skipExt) { + var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url, + parentPath; + + //If a colon is in the URL, it indicates a protocol is used and it is just + //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) + //or ends with .js, then assume the user meant to use an url and not a module id. + //The slash is important for protocol-less URLs as well as full paths. + if (req.jsExtRegExp.test(moduleName)) { + //Just a plain path, not module name lookup, so just return it. + //Add extension if it is included. This is a bit wonky, only non-.js things pass + //an extension, this method probably needs to be reworked. + url = moduleName + (ext || ''); + } else { + //A module that needs to be converted to a path. + paths = config.paths; + pkgs = config.pkgs; + + syms = moduleName.split('/'); + //For each module name segment, see if there is a path + //registered for it. Start with most specific name + //and work up from it. + for (i = syms.length; i > 0; i -= 1) { + parentModule = syms.slice(0, i).join('/'); + pkg = getOwn(pkgs, parentModule); + parentPath = getOwn(paths, parentModule); + if (parentPath) { + //If an array, it means there are a few choices, + //Choose the one that is desired + if (isArray(parentPath)) { + parentPath = parentPath[0]; + } + syms.splice(0, i, parentPath); + break; + } else if (pkg) { + //If module name is just the package name, then looking + //for the main module. + if (moduleName === pkg.name) { + pkgPath = pkg.location + '/' + pkg.main; + } else { + pkgPath = pkg.location; + } + syms.splice(0, i, pkgPath); + break; + } + } + + //Join the path parts together, then figure out if baseUrl is needed. + url = syms.join('/'); + url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js')); + url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; + } + + return config.urlArgs ? url + + ((url.indexOf('?') === -1 ? '?' : '&') + + config.urlArgs) : url; + }, + + //Delegates to req.load. Broken out as a separate function to + //allow overriding in the optimizer. + load: function (id, url) { + req.load(context, id, url); + }, + + /** + * Executes a module callback function. Broken out as a separate function + * solely to allow the build system to sequence the files in the built + * layer in the right sequence. + * + * @private + */ + execCb: function (name, callback, args, exports) { + return callback.apply(exports, args); + }, + + /** + * callback for script loads, used to check status of loading. + * + * @param {Event} evt the event from the browser for the script + * that was loaded. + */ + onScriptLoad: function (evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + if (evt.type === 'load' || + (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { + //Reset interactive script so a script node is not held onto for + //to long. + interactiveScript = null; + + //Pull out the name of the module and the context. + var data = getScriptData(evt); + context.completeLoad(data.id); + } + }, + + /** + * Callback for script errors. + */ + onScriptError: function (evt) { + var data = getScriptData(evt); + if (!hasPathFallback(data.id)) { + return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id])); + } + } + }; + + context.require = context.makeRequire(); + return context; + } + + /** + * Main entry point. + * + * If the only argument to require is a string, then the module that + * is represented by that string is fetched for the appropriate context. + * + * If the first argument is an array, then it will be treated as an array + * of dependency string names to fetch. An optional function callback can + * be specified to execute when all of those dependencies are available. + * + * Make a local req variable to help Caja compliance (it assumes things + * on a require that are not standardized), and to give a short + * name for minification/local scope use. + */ + req = requirejs = function (deps, callback, errback, optional) { + + //Find the right context, use default + var context, config, + contextName = defContextName; + + // Determine if have config object in the call. + if (!isArray(deps) && typeof deps !== 'string') { + // deps is a config object + config = deps; + if (isArray(callback)) { + // Adjust args if there are dependencies + deps = callback; + callback = errback; + errback = optional; + } else { + deps = []; + } + } + + if (config && config.context) { + contextName = config.context; + } + + context = getOwn(contexts, contextName); + if (!context) { + context = contexts[contextName] = req.s.newContext(contextName); + } + + if (config) { + context.configure(config); + } + + return context.require(deps, callback, errback); + }; + + /** + * Support require.config() to make it easier to cooperate with other + * AMD loaders on globally agreed names. + */ + req.config = function (config) { + return req(config); + }; + + /** + * Execute something after the current tick + * of the event loop. Override for other envs + * that have a better solution than setTimeout. + * @param {Function} fn function to execute later. + */ + req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) { + setTimeout(fn, 4); + } : function (fn) { fn(); }; + + /** + * Export require as a global, but only if it does not already exist. + */ + if (!require) { + require = req; + } + + req.version = version; + + //Used to filter out dependencies that are already paths. + req.jsExtRegExp = /^\/|:|\?|\.js$/; + req.isBrowser = isBrowser; + s = req.s = { + contexts: contexts, + newContext: newContext + }; + + //Create default context. + req({}); + + //Exports some context-sensitive methods on global require. + each([ + 'toUrl', + 'undef', + 'defined', + 'specified' + ], function (prop) { + //Reference from contexts instead of early binding to default context, + //so that during builds, the latest instance of the default context + //with its config gets used. + req[prop] = function () { + var ctx = contexts[defContextName]; + return ctx.require[prop].apply(ctx, arguments); + }; + }); + + if (isBrowser) { + head = s.head = document.getElementsByTagName('head')[0]; + //If BASE tag is in play, using appendChild is a problem for IE6. + //When that browser dies, this can be removed. Details in this jQuery bug: + //http://dev.jquery.com/ticket/2709 + baseElement = document.getElementsByTagName('base')[0]; + if (baseElement) { + head = s.head = baseElement.parentNode; + } + } + + /** + * Any errors that require explicitly generates will be passed to this + * function. Intercept/override it if you want custom error handling. + * @param {Error} err the error object. + */ + req.onError = defaultOnError; + + /** + * Creates the node for the load command. Only used in browser envs. + */ + req.createNode = function (config, moduleName, url) { + var node = config.xhtml ? + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); + node.type = config.scriptType || 'text/javascript'; + node.charset = 'utf-8'; + node.async = true; + return node; + }; + + /** + * Does the request to load a module for the browser case. + * Make this a separate function to allow other environments + * to override it. + * + * @param {Object} context the require context to find state. + * @param {String} moduleName the name of the module. + * @param {Object} url the URL to the module. + */ + req.load = function (context, moduleName, url) { + var config = (context && context.config) || {}, + node; + if (isBrowser) { + //In the browser so use a script tag + node = req.createNode(config, moduleName, url); + + node.setAttribute('data-requirecontext', context.contextName); + node.setAttribute('data-requiremodule', moduleName); + + //Set up load listener. Test attachEvent first because IE9 has + //a subtle issue in its addEventListener and script onload firings + //that do not match the behavior of all other browsers with + //addEventListener support, which fire the onload event for a + //script right after the script execution. See: + //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution + //UNFORTUNATELY Opera implements attachEvent but does not follow the script + //script execution mode. + if (node.attachEvent && + //Check if node.attachEvent is artificially added by custom script or + //natively supported by browser + //read https://github.com/jrburke/requirejs/issues/187 + //if we can NOT find [native code] then it must NOT natively supported. + //in IE8, node.attachEvent does not have toString() + //Note the test for "[native code" with no closing brace, see: + //https://github.com/jrburke/requirejs/issues/273 + !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && + !isOpera) { + //Probably IE. IE (at least 6-8) do not fire + //script onload right after executing the script, so + //we cannot tie the anonymous define call to a name. + //However, IE reports the script as being in 'interactive' + //readyState at the time of the define call. + useInteractive = true; + + node.attachEvent('onreadystatechange', context.onScriptLoad); + //It would be great to add an error handler here to catch + //404s in IE9+. However, onreadystatechange will fire before + //the error handler, so that does not help. If addEventListener + //is used, then IE will fire error before load, but we cannot + //use that pathway given the connect.microsoft.com issue + //mentioned above about not doing the 'script execute, + //then fire the script load event listener before execute + //next script' that other browsers do. + //Best hope: IE10 fixes the issues, + //and then destroys all installs of IE 6-9. + //node.attachEvent('onerror', context.onScriptError); + } else { + node.addEventListener('load', context.onScriptLoad, false); + node.addEventListener('error', context.onScriptError, false); + } + node.src = url; + + //For some cache cases in IE 6-8, the script executes before the end + //of the appendChild execution, so to tie an anonymous define + //call to the module name (which is stored on the node), hold on + //to a reference to this node, but clear after the DOM insertion. + currentlyAddingScript = node; + if (baseElement) { + head.insertBefore(node, baseElement); + } else { + head.appendChild(node); + } + currentlyAddingScript = null; + + return node; + } else if (isWebWorker) { + try { + //In a web worker, use importScripts. This is not a very + //efficient use of importScripts, importScripts will block until + //its script is downloaded and evaluated. However, if web workers + //are in play, the expectation that a build has been done so that + //only one script needs to be loaded anyway. This may need to be + //reevaluated if other use cases become common. + importScripts(url); + + //Account for anonymous modules + context.completeLoad(moduleName); + } catch (e) { + context.onError(makeError('importscripts', + 'importScripts failed for ' + + moduleName + ' at ' + url, + e, + [moduleName])); + } + } + }; + + function getInteractiveScript() { + if (interactiveScript && interactiveScript.readyState === 'interactive') { + return interactiveScript; + } + + eachReverse(scripts(), function (script) { + if (script.readyState === 'interactive') { + return (interactiveScript = script); + } + }); + return interactiveScript; + } + + //Look for a data-main script attribute, which could also adjust the baseUrl. + if (isBrowser && !cfg.skipDataMain) { + //Figure out baseUrl. Get it from the script tag with require.js in it. + eachReverse(scripts(), function (script) { + //Set the 'head' where we can append children by + //using the script's parent. + if (!head) { + head = script.parentNode; + } + + //Look for a data-main attribute to set main script for the page + //to load. If it is there, the path to data main becomes the + //baseUrl, if it is not already set. + dataMain = script.getAttribute('data-main'); + if (dataMain) { + //Preserve dataMain in case it is a path (i.e. contains '?') + mainScript = dataMain; + + //Set final baseUrl if there is not already an explicit one. + if (!cfg.baseUrl) { + //Pull off the directory of data-main for use as the + //baseUrl. + src = mainScript.split('/'); + mainScript = src.pop(); + subPath = src.length ? src.join('/') + '/' : './'; + + cfg.baseUrl = subPath; + } + + //Strip off any trailing .js since mainScript is now + //like a module name. + mainScript = mainScript.replace(jsSuffixRegExp, ''); + + //If mainScript is still a path, fall back to dataMain + if (req.jsExtRegExp.test(mainScript)) { + mainScript = dataMain; + } + + //Put the data-main script in the files to load. + cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript]; + + return true; + } + }); + } + + /** + * The function that handles definitions of modules. Differs from + * require() in that a string for the module should be the first argument, + * and the function to execute after dependencies are loaded should + * return a value to define the module corresponding to the first argument's + * name. + */ + define = function (name, deps, callback) { + var node, context; + + //Allow for anonymous modules + if (typeof name !== 'string') { + //Adjust args appropriately + callback = deps; + deps = name; + name = null; + } + + //This module may not have dependencies + if (!isArray(deps)) { + callback = deps; + deps = null; + } + + //If no name, and callback is a function, then figure out if it a + //CommonJS thing with dependencies. + if (!deps && isFunction(callback)) { + deps = []; + //Remove comments from the callback string, + //look for require calls, and pull them into the dependencies, + //but only if there are function args. + if (callback.length) { + callback + .toString() + .replace(commentRegExp, '') + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + + //May be a CommonJS thing even without require calls, but still + //could use exports, and module. Avoid doing exports and module + //work though if it just needs require. + //REQUIRES the function to expect the CommonJS variables in the + //order listed below. + deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); + } + } + + //If in IE 6-8 and hit an anonymous define() call, do the interactive + //work. + if (useInteractive) { + node = currentlyAddingScript || getInteractiveScript(); + if (node) { + if (!name) { + name = node.getAttribute('data-requiremodule'); + } + context = contexts[node.getAttribute('data-requirecontext')]; + } + } + + //Always save off evaluating the def call until the script onload handler. + //This allows multiple modules to be in a file without prematurely + //tracing dependencies, and allows for anonymous module support, + //where the module name is not known until the script onload event + //occurs. If no context, use the global queue, and get it processed + //in the onscript load callback. + (context ? context.defQueue : globalDefQueue).push([name, deps, callback]); + }; + + define.amd = { + jQuery: true + }; + + + /** + * Executes the text. Normally just uses eval, but can be modified + * to use a better, environment-specific call. Only used for transpiling + * loader plugins, not for plain JS modules. + * @param {String} text the text to execute/evaluate. + */ + req.exec = function (text) { + /*jslint evil: true */ + return eval(text); + }; + + //Set up with config info. + req(cfg); +}(this)); + + + + this.requirejsVars = { + require: require, + requirejs: require, + define: define + }; + + if (env === 'browser') { + /** + * @license RequireJS rhino Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +//sloppy since eval enclosed with use strict causes problems if the source +//text is not strict-compliant. +/*jslint sloppy: true, evil: true */ +/*global require, XMLHttpRequest */ + +(function () { + require.load = function (context, moduleName, url) { + var xhr = new XMLHttpRequest(); + + xhr.open('GET', url, true); + xhr.send(); + + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + eval(xhr.responseText); + + //Support anonymous modules. + context.completeLoad(moduleName); + } + }; + }; +}()); + } else if (env === 'rhino') { + /** + * @license RequireJS rhino Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint */ +/*global require: false, java: false, load: false */ + +(function () { + 'use strict'; + require.load = function (context, moduleName, url) { + + load(url); + + //Support anonymous modules. + context.completeLoad(moduleName); + }; + +}()); + } else if (env === 'node') { + this.requirejsVars.nodeRequire = nodeRequire; + require.nodeRequire = nodeRequire; + + /** + * @license RequireJS node Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint regexp: false */ +/*global require: false, define: false, requirejsVars: false, process: false */ + +/** + * This adapter assumes that x.js has loaded it and set up + * some variables. This adapter just allows limited RequireJS + * usage from within the requirejs directory. The general + * node adapater is r.js. + */ + +(function () { + 'use strict'; + + var nodeReq = requirejsVars.nodeRequire, + req = requirejsVars.require, + def = requirejsVars.define, + fs = nodeReq('fs'), + path = nodeReq('path'), + vm = nodeReq('vm'), + //In Node 0.7+ existsSync is on fs. + exists = fs.existsSync || path.existsSync, + hasOwn = Object.prototype.hasOwnProperty; + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + function syncTick(fn) { + fn(); + } + + function makeError(message, moduleName) { + var err = new Error(message); + err.requireModules = [moduleName]; + return err; + } + + //Supply an implementation that allows synchronous get of a module. + req.get = function (context, moduleName, relModuleMap, localRequire) { + if (moduleName === "require" || moduleName === "exports" || moduleName === "module") { + context.onError(makeError("Explicit require of " + moduleName + " is not allowed.", moduleName)); + } + + var ret, oldTick, + moduleMap = context.makeModuleMap(moduleName, relModuleMap, false, true); + + //Normalize module name, if it contains . or .. + moduleName = moduleMap.id; + + if (hasProp(context.defined, moduleName)) { + ret = context.defined[moduleName]; + } else { + if (ret === undefined) { + //Make sure nextTick for this type of call is sync-based. + oldTick = context.nextTick; + context.nextTick = syncTick; + try { + if (moduleMap.prefix) { + //A plugin, call requirejs to handle it. Now that + //nextTick is syncTick, the require will complete + //synchronously. + localRequire([moduleMap.originalName]); + + //Now that plugin is loaded, can regenerate the moduleMap + //to get the final, normalized ID. + moduleMap = context.makeModuleMap(moduleMap.originalName, relModuleMap, false, true); + moduleName = moduleMap.id; + } else { + //Try to dynamically fetch it. + req.load(context, moduleName, moduleMap.url); + + //Enable the module + context.enable(moduleMap, relModuleMap); + } + + //Break any cycles by requiring it normally, but this will + //finish synchronously + require([moduleName]); + + //The above calls are sync, so can do the next thing safely. + ret = context.defined[moduleName]; + } finally { + context.nextTick = oldTick; + } + } + } + + return ret; + }; + + req.nextTick = function (fn) { + process.nextTick(fn); + }; + + //Add wrapper around the code so that it gets the requirejs + //API instead of the Node API, and it is done lexically so + //that it survives later execution. + req.makeNodeWrapper = function (contents) { + return '(function (require, requirejs, define) { ' + + contents + + '\n}(requirejsVars.require, requirejsVars.requirejs, requirejsVars.define));'; + }; + + req.load = function (context, moduleName, url) { + var contents, err, + config = context.config; + + if (config.shim[moduleName] && (!config.suppress || !config.suppress.nodeShim)) { + console.warn('Shim config not supported in Node, may or may not work. Detected ' + + 'for module: ' + moduleName); + } + + if (exists(url)) { + contents = fs.readFileSync(url, 'utf8'); + + contents = req.makeNodeWrapper(contents); + try { + vm.runInThisContext(contents, fs.realpathSync(url)); + } catch (e) { + err = new Error('Evaluating ' + url + ' as module "' + + moduleName + '" failed with error: ' + e); + err.originalError = e; + err.moduleName = moduleName; + err.requireModules = [moduleName]; + err.fileName = url; + return context.onError(err); + } + } else { + def(moduleName, function () { + //Get the original name, since relative requires may be + //resolved differently in node (issue #202). Also, if relative, + //make it relative to the URL of the item requesting it + //(issue #393) + var dirName, + map = hasProp(context.registry, moduleName) && + context.registry[moduleName].map, + parentMap = map && map.parentMap, + originalName = map && map.originalName; + + if (originalName.charAt(0) === '.' && parentMap) { + dirName = parentMap.url.split('/'); + dirName.pop(); + originalName = dirName.join('/') + '/' + originalName; + } + + try { + return (context.config.nodeRequire || req.nodeRequire)(originalName); + } catch (e) { + err = new Error('Tried loading "' + moduleName + '" at ' + + url + ' then tried node\'s require("' + + originalName + '") and it failed ' + + 'with error: ' + e); + err.originalError = e; + err.moduleName = originalName; + err.requireModules = [moduleName]; + return context.onError(err); + } + }); + } + + //Support anonymous modules. + context.completeLoad(moduleName); + }; + + //Override to provide the function wrapper for define/require. + req.exec = function (text) { + /*jslint evil: true */ + text = req.makeNodeWrapper(text); + return eval(text); + }; +}()); + + } else if (env === 'xpconnect') { + /** + * @license RequireJS xpconnect Copyright (c) 2013, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint */ +/*global require, load */ + +(function () { + 'use strict'; + require.load = function (context, moduleName, url) { + + load(url); + + //Support anonymous modules. + context.completeLoad(moduleName); + }; + +}()); + + } + + //Support a default file name to execute. Useful for hosted envs + //like Joyent where it defaults to a server.js as the only executed + //script. But only do it if this is not an optimization run. + if (commandOption !== 'o' && (!fileName || !jsSuffixRegExp.test(fileName))) { + fileName = 'main.js'; + } + + /** + * Loads the library files that can be used for the optimizer, or for other + * tasks. + */ + function loadLib() { + /** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global Packages: false, process: false, window: false, navigator: false, + document: false, define: false */ + +/** + * A plugin that modifies any /env/ path to be the right path based on + * the host environment. Right now only works for Node, Rhino and browser. + */ +(function () { + var pathRegExp = /(\/|^)env\/|\{env\}/, + env = 'unknown'; + + if (typeof Packages !== 'undefined') { + env = 'rhino'; + } else if (typeof process !== 'undefined' && process.versions && !!process.versions.node) { + env = 'node'; + } else if ((typeof navigator !== 'undefined' && typeof document !== 'undefined') || + (typeof importScripts !== 'undefined' && typeof self !== 'undefined')) { + env = 'browser'; + } else if (typeof Components !== 'undefined' && Components.classes && Components.interfaces) { + env = 'xpconnect'; + } + + define('env', { + get: function () { + return env; + }, + + load: function (name, req, load, config) { + //Allow override in the config. + if (config.env) { + env = config.env; + } + + name = name.replace(pathRegExp, function (match, prefix) { + if (match.indexOf('{') === -1) { + return prefix + env + '/'; + } else { + return env; + } + }); + + req([name], function (mod) { + load(mod); + }); + } + }); +}());/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint plusplus: true */ +/*global define */ + +define('lang', function () { + 'use strict'; + + var lang, + hasOwn = Object.prototype.hasOwnProperty; + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + lang = { + backSlashRegExp: /\\/g, + ostring: Object.prototype.toString, + + isArray: Array.isArray || function (it) { + return lang.ostring.call(it) === "[object Array]"; + }, + + isFunction: function(it) { + return lang.ostring.call(it) === "[object Function]"; + }, + + isRegExp: function(it) { + return it && it instanceof RegExp; + }, + + hasProp: hasProp, + + //returns true if the object does not have an own property prop, + //or if it does, it is a falsy value. + falseProp: function (obj, prop) { + return !hasProp(obj, prop) || !obj[prop]; + }, + + //gets own property value for given prop on object + getOwn: function (obj, prop) { + return hasProp(obj, prop) && obj[prop]; + }, + + _mixin: function(dest, source, override){ + var name; + for (name in source) { + if(source.hasOwnProperty(name) && + (override || !dest.hasOwnProperty(name))) { + dest[name] = source[name]; + } + } + + return dest; // Object + }, + + /** + * mixin({}, obj1, obj2) is allowed. If the last argument is a boolean, + * then the source objects properties are force copied over to dest. + */ + mixin: function(dest){ + var parameters = Array.prototype.slice.call(arguments), + override, i, l; + + if (!dest) { dest = {}; } + + if (parameters.length > 2 && typeof arguments[parameters.length-1] === 'boolean') { + override = parameters.pop(); + } + + for (i = 1, l = parameters.length; i < l; i++) { + lang._mixin(dest, parameters[i], override); + } + return dest; // Object + }, + + + /** + * Does a type of deep copy. Do not give it anything fancy, best + * for basic object copies of objects that also work well as + * JSON-serialized things, or has properties pointing to functions. + * For non-array/object values, just returns the same object. + * @param {Object} obj copy properties from this object + * @param {Object} [result] optional result object to use + * @return {Object} + */ + deeplikeCopy: function (obj) { + var type, result; + + if (lang.isArray(obj)) { + result = []; + obj.forEach(function(value) { + result.push(lang.deeplikeCopy(value)); + }); + return result; + } + + type = typeof obj; + if (obj === null || obj === undefined || type === 'boolean' || + type === 'string' || type === 'number' || lang.isFunction(obj) || + lang.isRegExp(obj)) { + return obj; + } + + //Anything else is an object, hopefully. + result = {}; + lang.eachProp(obj, function(value, key) { + result[key] = lang.deeplikeCopy(value); + }); + return result; + }, + + delegate: (function () { + // boodman/crockford delegation w/ cornford optimization + function TMP() {} + return function (obj, props) { + TMP.prototype = obj; + var tmp = new TMP(); + TMP.prototype = null; + if (props) { + lang.mixin(tmp, props); + } + return tmp; // Object + }; + }()), + + /** + * Helper function for iterating over an array. If the func returns + * a true value, it will break out of the loop. + */ + each: function each(ary, func) { + if (ary) { + var i; + for (i = 0; i < ary.length; i += 1) { + if (func(ary[i], i, ary)) { + break; + } + } + } + }, + + /** + * Cycles over properties in an object and calls a function for each + * property value. If the function returns a truthy value, then the + * iteration is stopped. + */ + eachProp: function eachProp(obj, func) { + var prop; + for (prop in obj) { + if (hasProp(obj, prop)) { + if (func(obj[prop], prop)) { + break; + } + } + } + }, + + //Similar to Function.prototype.bind, but the "this" object is specified + //first, since it is easier to read/figure out what "this" will be. + bind: function bind(obj, fn) { + return function () { + return fn.apply(obj, arguments); + }; + }, + + //Escapes a content string to be be a string that has characters escaped + //for inclusion as part of a JS string. + jsEscape: function (content) { + return content.replace(/(["'\\])/g, '\\$1') + .replace(/[\f]/g, "\\f") + .replace(/[\b]/g, "\\b") + .replace(/[\n]/g, "\\n") + .replace(/[\t]/g, "\\t") + .replace(/[\r]/g, "\\r"); + } + }; + return lang; +}); +/** + * prim 0.0.1 Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/requirejs/prim for details + */ + +/*global setImmediate, process, setTimeout, define, module */ + +//Set prime.hideResolutionConflict = true to allow "resolution-races" +//in promise-tests to pass. +//Since the goal of prim is to be a small impl for trusted code, it is +//more important to normally throw in this case so that we can find +//logic errors quicker. + +var prim; +(function () { + 'use strict'; + var op = Object.prototype, + hasOwn = op.hasOwnProperty; + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + /** + * Helper function for iterating over an array. If the func returns + * a true value, it will break out of the loop. + */ + function each(ary, func) { + if (ary) { + var i; + for (i = 0; i < ary.length; i += 1) { + if (ary[i]) { + func(ary[i], i, ary); + } + } + } + } + + function check(p) { + if (hasProp(p, 'e') || hasProp(p, 'v')) { + if (!prim.hideResolutionConflict) { + throw new Error('nope'); + } + return false; + } + return true; + } + + function notify(ary, value) { + prim.nextTick(function () { + each(ary, function (item) { + item(value); + }); + }); + } + + prim = function prim() { + var p, + ok = [], + fail = []; + + return (p = { + callback: function (yes, no) { + if (no) { + p.errback(no); + } + + if (hasProp(p, 'v')) { + prim.nextTick(function () { + yes(p.v); + }); + } else { + ok.push(yes); + } + }, + + errback: function (no) { + if (hasProp(p, 'e')) { + prim.nextTick(function () { + no(p.e); + }); + } else { + fail.push(no); + } + }, + + finished: function () { + return hasProp(p, 'e') || hasProp(p, 'v'); + }, + + rejected: function () { + return hasProp(p, 'e'); + }, + + resolve: function (v) { + if (check(p)) { + p.v = v; + notify(ok, v); + } + return p; + }, + reject: function (e) { + if (check(p)) { + p.e = e; + notify(fail, e); + } + return p; + }, + + start: function (fn) { + p.resolve(); + return p.promise.then(fn); + }, + + promise: { + then: function (yes, no) { + var next = prim(); + + p.callback(function (v) { + try { + if (yes && typeof yes === 'function') { + v = yes(v); + } + + if (v && v.then) { + v.then(next.resolve, next.reject); + } else { + next.resolve(v); + } + } catch (e) { + next.reject(e); + } + }, function (e) { + var err; + + try { + if (!no || typeof no !== 'function') { + next.reject(e); + } else { + err = no(e); + + if (err && err.then) { + err.then(next.resolve, next.reject); + } else { + next.resolve(err); + } + } + } catch (e2) { + next.reject(e2); + } + }); + + return next.promise; + }, + + fail: function (no) { + return p.promise.then(null, no); + }, + + end: function () { + p.errback(function (e) { + throw e; + }); + } + } + }); + }; + + prim.serial = function (ary) { + var result = prim().resolve().promise; + each(ary, function (item) { + result = result.then(function () { + return item(); + }); + }); + return result; + }; + + prim.nextTick = typeof setImmediate === 'function' ? setImmediate : + (typeof process !== 'undefined' && process.nextTick ? + process.nextTick : (typeof setTimeout !== 'undefined' ? + function (fn) { + setTimeout(fn, 0); + } : function (fn) { + fn(); + })); + + if (typeof define === 'function' && define.amd) { + define('prim', function () { return prim; }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = prim; + } +}()); +if(env === 'browser') { +/** + * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, load: false */ + +//Just a stub for use with uglify's consolidator.js +define('browser/assert', function () { + return {}; +}); + +} + +if(env === 'node') { +/** + * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, load: false */ + +//Needed so that rhino/assert can return a stub for uglify's consolidator.js +define('node/assert', ['assert'], function (assert) { + return assert; +}); + +} + +if(env === 'rhino') { +/** + * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, load: false */ + +//Just a stub for use with uglify's consolidator.js +define('rhino/assert', function () { + return {}; +}); + +} + +if(env === 'xpconnect') { +/** + * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, load: false */ + +//Just a stub for use with uglify's consolidator.js +define('xpconnect/assert', function () { + return {}; +}); + +} + +if(env === 'browser') { +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, process: false */ + +define('browser/args', function () { + //Always expect config via an API call + return []; +}); + +} + +if(env === 'node') { +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, process: false */ + +define('node/args', function () { + //Do not return the "node" or "r.js" arguments + var args = process.argv.slice(2); + + //Ignore any command option used for main x.js branching + if (args[0] && args[0].indexOf('-') === 0) { + args = args.slice(1); + } + + return args; +}); + +} + +if(env === 'rhino') { +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, process: false */ + +var jsLibRhinoArgs = (typeof rhinoArgs !== 'undefined' && rhinoArgs) || [].concat(Array.prototype.slice.call(arguments, 0)); + +define('rhino/args', function () { + var args = jsLibRhinoArgs; + + //Ignore any command option used for main x.js branching + if (args[0] && args[0].indexOf('-') === 0) { + args = args.slice(1); + } + + return args; +}); + +} + +if(env === 'xpconnect') { +/** + * @license Copyright (c) 2013, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define, xpconnectArgs */ + +var jsLibXpConnectArgs = (typeof xpconnectArgs !== 'undefined' && xpconnectArgs) || [].concat(Array.prototype.slice.call(arguments, 0)); + +define('xpconnect/args', function () { + var args = jsLibXpConnectArgs; + + //Ignore any command option used for main x.js branching + if (args[0] && args[0].indexOf('-') === 0) { + args = args.slice(1); + } + + return args; +}); + +} + +if(env === 'browser') { +/** + * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, console: false */ + +define('browser/load', ['./file'], function (file) { + function load(fileName) { + eval(file.readFile(fileName)); + } + + return load; +}); + +} + +if(env === 'node') { +/** + * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, console: false */ + +define('node/load', ['fs'], function (fs) { + function load(fileName) { + var contents = fs.readFileSync(fileName, 'utf8'); + process.compile(contents, fileName); + } + + return load; +}); + +} + +if(env === 'rhino') { +/** + * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, load: false */ + +define('rhino/load', function () { + return load; +}); + +} + +if(env === 'xpconnect') { +/** + * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, load: false */ + +define('xpconnect/load', function () { + return load; +}); + +} + +if(env === 'browser') { +/** + * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint sloppy: true, nomen: true */ +/*global require, define, console, XMLHttpRequest, requirejs, location */ + +define('browser/file', ['prim'], function (prim) { + + var file, + currDirRegExp = /^\.(\/|$)/; + + function frontSlash(path) { + return path.replace(/\\/g, '/'); + } + + function exists(path) { + var status, xhr = new XMLHttpRequest(); + + //Oh yeah, that is right SYNC IO. Behold its glory + //and horrible blocking behavior. + xhr.open('HEAD', path, false); + xhr.send(); + status = xhr.status; + + return status === 200 || status === 304; + } + + function mkDir(dir) { + console.log('mkDir is no-op in browser'); + } + + function mkFullDir(dir) { + console.log('mkFullDir is no-op in browser'); + } + + file = { + backSlashRegExp: /\\/g, + exclusionRegExp: /^\./, + getLineSeparator: function () { + return '/'; + }, + + exists: function (fileName) { + return exists(fileName); + }, + + parent: function (fileName) { + var parts = fileName.split('/'); + parts.pop(); + return parts.join('/'); + }, + + /** + * Gets the absolute file path as a string, normalized + * to using front slashes for path separators. + * @param {String} fileName + */ + absPath: function (fileName) { + var dir; + if (currDirRegExp.test(fileName)) { + dir = frontSlash(location.href); + if (dir.indexOf('/') !== -1) { + dir = dir.split('/'); + + //Pull off protocol and host, just want + //to allow paths (other build parts, like + //require._isSupportedBuildUrl do not support + //full URLs), but a full path from + //the root. + dir.splice(0, 3); + + dir.pop(); + dir = '/' + dir.join('/'); + } + + fileName = dir + fileName.substring(1); + } + + return fileName; + }, + + normalize: function (fileName) { + return fileName; + }, + + isFile: function (path) { + return true; + }, + + isDirectory: function (path) { + return false; + }, + + getFilteredFileList: function (startDir, regExpFilters, makeUnixPaths) { + console.log('file.getFilteredFileList is no-op in browser'); + }, + + copyDir: function (srcDir, destDir, regExpFilter, onlyCopyNew) { + console.log('file.copyDir is no-op in browser'); + + }, + + copyFile: function (srcFileName, destFileName, onlyCopyNew) { + console.log('file.copyFile is no-op in browser'); + }, + + /** + * Renames a file. May fail if "to" already exists or is on another drive. + */ + renameFile: function (from, to) { + console.log('file.renameFile is no-op in browser'); + }, + + /** + * Reads a *text* file. + */ + readFile: function (path, encoding) { + var xhr = new XMLHttpRequest(); + + //Oh yeah, that is right SYNC IO. Behold its glory + //and horrible blocking behavior. + xhr.open('GET', path, false); + xhr.send(); + + return xhr.responseText; + }, + + readFileAsync: function (path, encoding) { + var xhr = new XMLHttpRequest(), + d = prim(); + + xhr.open('GET', path, true); + xhr.send(); + + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status > 400) { + d.reject(new Error('Status: ' + xhr.status + ': ' + xhr.statusText)); + } else { + d.resolve(xhr.responseText); + } + } + }; + + return d.promise; + }, + + saveUtf8File: function (fileName, fileContents) { + //summary: saves a *text* file using UTF-8 encoding. + file.saveFile(fileName, fileContents, "utf8"); + }, + + saveFile: function (fileName, fileContents, encoding) { + requirejs.browser.saveFile(fileName, fileContents, encoding); + }, + + deleteFile: function (fileName) { + console.log('file.deleteFile is no-op in browser'); + }, + + /** + * Deletes any empty directories under the given directory. + */ + deleteEmptyDirs: function (startDir) { + console.log('file.deleteEmptyDirs is no-op in browser'); + } + }; + + return file; + +}); + +} + +if(env === 'node') { +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint plusplus: false, octal:false, strict: false */ +/*global define: false, process: false */ + +define('node/file', ['fs', 'path', 'prim'], function (fs, path, prim) { + + var isWindows = process.platform === 'win32', + windowsDriveRegExp = /^[a-zA-Z]\:\/$/, + file; + + function frontSlash(path) { + return path.replace(/\\/g, '/'); + } + + function exists(path) { + if (isWindows && path.charAt(path.length - 1) === '/' && + path.charAt(path.length - 2) !== ':') { + path = path.substring(0, path.length - 1); + } + + try { + fs.statSync(path); + return true; + } catch (e) { + return false; + } + } + + function mkDir(dir) { + if (!exists(dir) && (!isWindows || !windowsDriveRegExp.test(dir))) { + fs.mkdirSync(dir, 511); + } + } + + function mkFullDir(dir) { + var parts = dir.split('/'), + currDir = '', + first = true; + + parts.forEach(function (part) { + //First part may be empty string if path starts with a slash. + currDir += part + '/'; + first = false; + + if (part) { + mkDir(currDir); + } + }); + } + + file = { + backSlashRegExp: /\\/g, + exclusionRegExp: /^\./, + getLineSeparator: function () { + return '/'; + }, + + exists: function (fileName) { + return exists(fileName); + }, + + parent: function (fileName) { + var parts = fileName.split('/'); + parts.pop(); + return parts.join('/'); + }, + + /** + * Gets the absolute file path as a string, normalized + * to using front slashes for path separators. + * @param {String} fileName + */ + absPath: function (fileName) { + return frontSlash(path.normalize(frontSlash(fs.realpathSync(fileName)))); + }, + + normalize: function (fileName) { + return frontSlash(path.normalize(fileName)); + }, + + isFile: function (path) { + return fs.statSync(path).isFile(); + }, + + isDirectory: function (path) { + return fs.statSync(path).isDirectory(); + }, + + getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths) { + //summary: Recurses startDir and finds matches to the files that match regExpFilters.include + //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters, + //and it will be treated as the "include" case. + //Ignores files/directories that start with a period (.) unless exclusionRegExp + //is set to another value. + var files = [], topDir, regExpInclude, regExpExclude, dirFileArray, + i, stat, filePath, ok, dirFiles, fileName; + + topDir = startDir; + + regExpInclude = regExpFilters.include || regExpFilters; + regExpExclude = regExpFilters.exclude || null; + + if (file.exists(topDir)) { + dirFileArray = fs.readdirSync(topDir); + for (i = 0; i < dirFileArray.length; i++) { + fileName = dirFileArray[i]; + filePath = path.join(topDir, fileName); + stat = fs.statSync(filePath); + if (stat.isFile()) { + if (makeUnixPaths) { + //Make sure we have a JS string. + if (filePath.indexOf("/") === -1) { + filePath = frontSlash(filePath); + } + } + + ok = true; + if (regExpInclude) { + ok = filePath.match(regExpInclude); + } + if (ok && regExpExclude) { + ok = !filePath.match(regExpExclude); + } + + if (ok && (!file.exclusionRegExp || + !file.exclusionRegExp.test(fileName))) { + files.push(filePath); + } + } else if (stat.isDirectory() && + (!file.exclusionRegExp || !file.exclusionRegExp.test(fileName))) { + dirFiles = this.getFilteredFileList(filePath, regExpFilters, makeUnixPaths); + files.push.apply(files, dirFiles); + } + } + } + + return files; //Array + }, + + copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) { + //summary: copies files from srcDir to destDir using the regExpFilter to determine if the + //file should be copied. Returns a list file name strings of the destinations that were copied. + regExpFilter = regExpFilter || /\w/; + + //Normalize th directory names, but keep front slashes. + //path module on windows now returns backslashed paths. + srcDir = frontSlash(path.normalize(srcDir)); + destDir = frontSlash(path.normalize(destDir)); + + var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true), + copiedFiles = [], i, srcFileName, destFileName; + + for (i = 0; i < fileNames.length; i++) { + srcFileName = fileNames[i]; + destFileName = srcFileName.replace(srcDir, destDir); + + if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) { + copiedFiles.push(destFileName); + } + } + + return copiedFiles.length ? copiedFiles : null; //Array or null + }, + + copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) { + //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if + //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred. + var parentDir; + + //logger.trace("Src filename: " + srcFileName); + //logger.trace("Dest filename: " + destFileName); + + //If onlyCopyNew is true, then compare dates and only copy if the src is newer + //than dest. + if (onlyCopyNew) { + if (file.exists(destFileName) && fs.statSync(destFileName).mtime.getTime() >= fs.statSync(srcFileName).mtime.getTime()) { + return false; //Boolean + } + } + + //Make sure destination dir exists. + parentDir = path.dirname(destFileName); + if (!file.exists(parentDir)) { + mkFullDir(parentDir); + } + + fs.writeFileSync(destFileName, fs.readFileSync(srcFileName, 'binary'), 'binary'); + + return true; //Boolean + }, + + /** + * Renames a file. May fail if "to" already exists or is on another drive. + */ + renameFile: function (from, to) { + return fs.renameSync(from, to); + }, + + /** + * Reads a *text* file. + */ + readFile: function (/*String*/path, /*String?*/encoding) { + if (encoding === 'utf-8') { + encoding = 'utf8'; + } + if (!encoding) { + encoding = 'utf8'; + } + + var text = fs.readFileSync(path, encoding); + + //Hmm, would not expect to get A BOM, but it seems to happen, + //remove it just in case. + if (text.indexOf('\uFEFF') === 0) { + text = text.substring(1, text.length); + } + + return text; + }, + + readFileAsync: function (path, encoding) { + var d = prim(); + try { + d.resolve(file.readFile(path, encoding)); + } catch (e) { + d.reject(e); + } + return d.promise; + }, + + saveUtf8File: function (/*String*/fileName, /*String*/fileContents) { + //summary: saves a *text* file using UTF-8 encoding. + file.saveFile(fileName, fileContents, "utf8"); + }, + + saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) { + //summary: saves a *text* file. + var parentDir; + + if (encoding === 'utf-8') { + encoding = 'utf8'; + } + if (!encoding) { + encoding = 'utf8'; + } + + //Make sure destination directories exist. + parentDir = path.dirname(fileName); + if (!file.exists(parentDir)) { + mkFullDir(parentDir); + } + + fs.writeFileSync(fileName, fileContents, encoding); + }, + + deleteFile: function (/*String*/fileName) { + //summary: deletes a file or directory if it exists. + var files, i, stat; + if (file.exists(fileName)) { + stat = fs.statSync(fileName); + if (stat.isDirectory()) { + files = fs.readdirSync(fileName); + for (i = 0; i < files.length; i++) { + this.deleteFile(path.join(fileName, files[i])); + } + fs.rmdirSync(fileName); + } else { + fs.unlinkSync(fileName); + } + } + }, + + + /** + * Deletes any empty directories under the given directory. + */ + deleteEmptyDirs: function (startDir) { + var dirFileArray, i, fileName, filePath, stat; + + if (file.exists(startDir)) { + dirFileArray = fs.readdirSync(startDir); + for (i = 0; i < dirFileArray.length; i++) { + fileName = dirFileArray[i]; + filePath = path.join(startDir, fileName); + stat = fs.statSync(filePath); + if (stat.isDirectory()) { + file.deleteEmptyDirs(filePath); + } + } + + //If directory is now empty, remove it. + if (fs.readdirSync(startDir).length === 0) { + file.deleteFile(startDir); + } + } + } + }; + + return file; + +}); + +} + +if(env === 'rhino') { +/** + * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +//Helper functions to deal with file I/O. + +/*jslint plusplus: false */ +/*global java: false, define: false */ + +define('rhino/file', ['prim'], function (prim) { + var file = { + backSlashRegExp: /\\/g, + + exclusionRegExp: /^\./, + + getLineSeparator: function () { + return file.lineSeparator; + }, + + lineSeparator: java.lang.System.getProperty("line.separator"), //Java String + + exists: function (fileName) { + return (new java.io.File(fileName)).exists(); + }, + + parent: function (fileName) { + return file.absPath((new java.io.File(fileName)).getParentFile()); + }, + + normalize: function (fileName) { + return file.absPath(fileName); + }, + + isFile: function (path) { + return (new java.io.File(path)).isFile(); + }, + + isDirectory: function (path) { + return (new java.io.File(path)).isDirectory(); + }, + + /** + * Gets the absolute file path as a string, normalized + * to using front slashes for path separators. + * @param {java.io.File||String} file + */ + absPath: function (fileObj) { + if (typeof fileObj === "string") { + fileObj = new java.io.File(fileObj); + } + return (fileObj.getCanonicalPath() + "").replace(file.backSlashRegExp, "/"); + }, + + getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths, /*boolean?*/startDirIsJavaObject) { + //summary: Recurses startDir and finds matches to the files that match regExpFilters.include + //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters, + //and it will be treated as the "include" case. + //Ignores files/directories that start with a period (.) unless exclusionRegExp + //is set to another value. + var files = [], topDir, regExpInclude, regExpExclude, dirFileArray, + i, fileObj, filePath, ok, dirFiles; + + topDir = startDir; + if (!startDirIsJavaObject) { + topDir = new java.io.File(startDir); + } + + regExpInclude = regExpFilters.include || regExpFilters; + regExpExclude = regExpFilters.exclude || null; + + if (topDir.exists()) { + dirFileArray = topDir.listFiles(); + for (i = 0; i < dirFileArray.length; i++) { + fileObj = dirFileArray[i]; + if (fileObj.isFile()) { + filePath = fileObj.getPath(); + if (makeUnixPaths) { + //Make sure we have a JS string. + filePath = String(filePath); + if (filePath.indexOf("/") === -1) { + filePath = filePath.replace(/\\/g, "/"); + } + } + + ok = true; + if (regExpInclude) { + ok = filePath.match(regExpInclude); + } + if (ok && regExpExclude) { + ok = !filePath.match(regExpExclude); + } + + if (ok && (!file.exclusionRegExp || + !file.exclusionRegExp.test(fileObj.getName()))) { + files.push(filePath); + } + } else if (fileObj.isDirectory() && + (!file.exclusionRegExp || !file.exclusionRegExp.test(fileObj.getName()))) { + dirFiles = this.getFilteredFileList(fileObj, regExpFilters, makeUnixPaths, true); + files.push.apply(files, dirFiles); + } + } + } + + return files; //Array + }, + + copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) { + //summary: copies files from srcDir to destDir using the regExpFilter to determine if the + //file should be copied. Returns a list file name strings of the destinations that were copied. + regExpFilter = regExpFilter || /\w/; + + var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true), + copiedFiles = [], i, srcFileName, destFileName; + + for (i = 0; i < fileNames.length; i++) { + srcFileName = fileNames[i]; + destFileName = srcFileName.replace(srcDir, destDir); + + if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) { + copiedFiles.push(destFileName); + } + } + + return copiedFiles.length ? copiedFiles : null; //Array or null + }, + + copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) { + //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if + //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred. + var destFile = new java.io.File(destFileName), srcFile, parentDir, + srcChannel, destChannel; + + //logger.trace("Src filename: " + srcFileName); + //logger.trace("Dest filename: " + destFileName); + + //If onlyCopyNew is true, then compare dates and only copy if the src is newer + //than dest. + if (onlyCopyNew) { + srcFile = new java.io.File(srcFileName); + if (destFile.exists() && destFile.lastModified() >= srcFile.lastModified()) { + return false; //Boolean + } + } + + //Make sure destination dir exists. + parentDir = destFile.getParentFile(); + if (!parentDir.exists()) { + if (!parentDir.mkdirs()) { + throw "Could not create directory: " + parentDir.getCanonicalPath(); + } + } + + //Java's version of copy file. + srcChannel = new java.io.FileInputStream(srcFileName).getChannel(); + destChannel = new java.io.FileOutputStream(destFileName).getChannel(); + destChannel.transferFrom(srcChannel, 0, srcChannel.size()); + srcChannel.close(); + destChannel.close(); + + return true; //Boolean + }, + + /** + * Renames a file. May fail if "to" already exists or is on another drive. + */ + renameFile: function (from, to) { + return (new java.io.File(from)).renameTo((new java.io.File(to))); + }, + + readFile: function (/*String*/path, /*String?*/encoding) { + //A file read function that can deal with BOMs + encoding = encoding || "utf-8"; + var fileObj = new java.io.File(path), + input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(fileObj), encoding)), + stringBuffer, line; + try { + stringBuffer = new java.lang.StringBuffer(); + line = input.readLine(); + + // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 + // http://www.unicode.org/faq/utf_bom.html + + // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 + if (line && line.length() && line.charAt(0) === 0xfeff) { + // Eat the BOM, since we've already found the encoding on this file, + // and we plan to concatenating this buffer with others; the BOM should + // only appear at the top of a file. + line = line.substring(1); + } + while (line !== null) { + stringBuffer.append(line); + stringBuffer.append(file.lineSeparator); + line = input.readLine(); + } + //Make sure we return a JavaScript string and not a Java string. + return String(stringBuffer.toString()); //String + } finally { + input.close(); + } + }, + + readFileAsync: function (path, encoding) { + var d = prim(); + try { + d.resolve(file.readFile(path, encoding)); + } catch (e) { + d.reject(e); + } + return d.promise; + }, + + saveUtf8File: function (/*String*/fileName, /*String*/fileContents) { + //summary: saves a file using UTF-8 encoding. + file.saveFile(fileName, fileContents, "utf-8"); + }, + + saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) { + //summary: saves a file. + var outFile = new java.io.File(fileName), outWriter, parentDir, os; + + parentDir = outFile.getAbsoluteFile().getParentFile(); + if (!parentDir.exists()) { + if (!parentDir.mkdirs()) { + throw "Could not create directory: " + parentDir.getAbsolutePath(); + } + } + + if (encoding) { + outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), encoding); + } else { + outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile)); + } + + os = new java.io.BufferedWriter(outWriter); + try { + os.write(fileContents); + } finally { + os.close(); + } + }, + + deleteFile: function (/*String*/fileName) { + //summary: deletes a file or directory if it exists. + var fileObj = new java.io.File(fileName), files, i; + if (fileObj.exists()) { + if (fileObj.isDirectory()) { + files = fileObj.listFiles(); + for (i = 0; i < files.length; i++) { + this.deleteFile(files[i]); + } + } + fileObj["delete"](); + } + }, + + /** + * Deletes any empty directories under the given directory. + * The startDirIsJavaObject is private to this implementation's + * recursion needs. + */ + deleteEmptyDirs: function (startDir, startDirIsJavaObject) { + var topDir = startDir, + dirFileArray, i, fileObj; + + if (!startDirIsJavaObject) { + topDir = new java.io.File(startDir); + } + + if (topDir.exists()) { + dirFileArray = topDir.listFiles(); + for (i = 0; i < dirFileArray.length; i++) { + fileObj = dirFileArray[i]; + if (fileObj.isDirectory()) { + file.deleteEmptyDirs(fileObj, true); + } + } + + //If the directory is empty now, delete it. + if (topDir.listFiles().length === 0) { + file.deleteFile(String(topDir.getPath())); + } + } + } + }; + + return file; +}); + +} + +if(env === 'xpconnect') { +/** + * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +//Helper functions to deal with file I/O. + +/*jslint plusplus: false */ +/*global define, Components, xpcUtil */ + +define('xpconnect/file', ['prim'], function (prim) { + var file, + Cc = Components.classes, + Ci = Components.interfaces, + //Depends on xpcUtil which is set up in x.js + xpfile = xpcUtil.xpfile; + + function mkFullDir(dirObj) { + //1 is DIRECTORY_TYPE, 511 is 0777 permissions + if (!dirObj.exists()) { + dirObj.create(1, 511); + } + } + + file = { + backSlashRegExp: /\\/g, + + exclusionRegExp: /^\./, + + getLineSeparator: function () { + return file.lineSeparator; + }, + + lineSeparator: ('@mozilla.org/windows-registry-key;1' in Cc) ? + '\r\n' : '\n', + + exists: function (fileName) { + return xpfile(fileName).exists(); + }, + + parent: function (fileName) { + return xpfile(fileName).parent; + }, + + normalize: function (fileName) { + return file.absPath(fileName); + }, + + isFile: function (path) { + return xpfile(path).isFile(); + }, + + isDirectory: function (path) { + return xpfile(path).isDirectory(); + }, + + /** + * Gets the absolute file path as a string, normalized + * to using front slashes for path separators. + * @param {java.io.File||String} file + */ + absPath: function (fileObj) { + if (typeof fileObj === "string") { + fileObj = xpfile(fileObj); + } + return fileObj.path; + }, + + getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths, /*boolean?*/startDirIsObject) { + //summary: Recurses startDir and finds matches to the files that match regExpFilters.include + //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters, + //and it will be treated as the "include" case. + //Ignores files/directories that start with a period (.) unless exclusionRegExp + //is set to another value. + var files = [], topDir, regExpInclude, regExpExclude, dirFileArray, + fileObj, filePath, ok, dirFiles; + + topDir = startDir; + if (!startDirIsObject) { + topDir = xpfile(startDir); + } + + regExpInclude = regExpFilters.include || regExpFilters; + regExpExclude = regExpFilters.exclude || null; + + if (topDir.exists()) { + dirFileArray = topDir.directoryEntries; + while (dirFileArray.hasMoreElements()) { + fileObj = dirFileArray.getNext().QueryInterface(Ci.nsILocalFile); + if (fileObj.isFile()) { + filePath = fileObj.path; + if (makeUnixPaths) { + if (filePath.indexOf("/") === -1) { + filePath = filePath.replace(/\\/g, "/"); + } + } + + ok = true; + if (regExpInclude) { + ok = filePath.match(regExpInclude); + } + if (ok && regExpExclude) { + ok = !filePath.match(regExpExclude); + } + + if (ok && (!file.exclusionRegExp || + !file.exclusionRegExp.test(fileObj.leafName))) { + files.push(filePath); + } + } else if (fileObj.isDirectory() && + (!file.exclusionRegExp || !file.exclusionRegExp.test(fileObj.leafName))) { + dirFiles = this.getFilteredFileList(fileObj, regExpFilters, makeUnixPaths, true); + files.push.apply(files, dirFiles); + } + } + } + + return files; //Array + }, + + copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) { + //summary: copies files from srcDir to destDir using the regExpFilter to determine if the + //file should be copied. Returns a list file name strings of the destinations that were copied. + regExpFilter = regExpFilter || /\w/; + + var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true), + copiedFiles = [], i, srcFileName, destFileName; + + for (i = 0; i < fileNames.length; i += 1) { + srcFileName = fileNames[i]; + destFileName = srcFileName.replace(srcDir, destDir); + + if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) { + copiedFiles.push(destFileName); + } + } + + return copiedFiles.length ? copiedFiles : null; //Array or null + }, + + copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) { + //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if + //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred. + var destFile = xpfile(destFileName), + srcFile = xpfile(srcFileName); + + //logger.trace("Src filename: " + srcFileName); + //logger.trace("Dest filename: " + destFileName); + + //If onlyCopyNew is true, then compare dates and only copy if the src is newer + //than dest. + if (onlyCopyNew) { + if (destFile.exists() && destFile.lastModifiedTime >= srcFile.lastModifiedTime) { + return false; //Boolean + } + } + + srcFile.copyTo(destFile.parent, destFile.leafName); + + return true; //Boolean + }, + + /** + * Renames a file. May fail if "to" already exists or is on another drive. + */ + renameFile: function (from, to) { + var toFile = xpfile(to); + return xpfile(from).moveTo(toFile.parent, toFile.leafName); + }, + + readFile: xpcUtil.readFile, + + readFileAsync: function (path, encoding) { + var d = prim(); + try { + d.resolve(file.readFile(path, encoding)); + } catch (e) { + d.reject(e); + } + return d.promise; + }, + + saveUtf8File: function (/*String*/fileName, /*String*/fileContents) { + //summary: saves a file using UTF-8 encoding. + file.saveFile(fileName, fileContents, "utf-8"); + }, + + saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) { + var outStream, convertStream, + fileObj = xpfile(fileName); + + mkFullDir(fileObj.parent); + + try { + outStream = Cc['@mozilla.org/network/file-output-stream;1'] + .createInstance(Ci.nsIFileOutputStream); + //438 is decimal for 0777 + outStream.init(fileObj, 0x02 | 0x08 | 0x20, 511, 0); + + convertStream = Cc['@mozilla.org/intl/converter-output-stream;1'] + .createInstance(Ci.nsIConverterOutputStream); + + convertStream.init(outStream, encoding, 0, 0); + convertStream.writeString(fileContents); + } catch (e) { + throw new Error((fileObj && fileObj.path || '') + ': ' + e); + } finally { + if (convertStream) { + convertStream.close(); + } + if (outStream) { + outStream.close(); + } + } + }, + + deleteFile: function (/*String*/fileName) { + //summary: deletes a file or directory if it exists. + var fileObj = xpfile(fileName); + if (fileObj.exists()) { + fileObj.remove(true); + } + }, + + /** + * Deletes any empty directories under the given directory. + * The startDirIsJavaObject is private to this implementation's + * recursion needs. + */ + deleteEmptyDirs: function (startDir, startDirIsObject) { + var topDir = startDir, + dirFileArray, fileObj; + + if (!startDirIsObject) { + topDir = xpfile(startDir); + } + + if (topDir.exists()) { + dirFileArray = topDir.directoryEntries; + while (dirFileArray.hasMoreElements()) { + fileObj = dirFileArray.getNext().QueryInterface(Ci.nsILocalFile); + + if (fileObj.isDirectory()) { + file.deleteEmptyDirs(fileObj, true); + } + } + + //If the directory is empty now, delete it. + dirFileArray = topDir.directoryEntries; + if (!dirFileArray.hasMoreElements()) { + file.deleteFile(topDir.path); + } + } + } + }; + + return file; +}); + +} + +if(env === 'browser') { +/*global process */ +define('browser/quit', function () { + 'use strict'; + return function (code) { + }; +}); +} + +if(env === 'node') { +/*global process */ +define('node/quit', function () { + 'use strict'; + return function (code) { + var draining = 0; + var exit = function () { + if (draining === 0) { + process.exit(code); + } else { + draining -= 1; + } + }; + if (process.stdout.bufferSize) { + draining += 1; + process.stdout.once('drain', exit); + } + if (process.stderr.bufferSize) { + draining += 1; + process.stderr.once('drain', exit); + } + exit(); + }; +}); + +} + +if(env === 'rhino') { +/*global quit */ +define('rhino/quit', function () { + 'use strict'; + return function (code) { + return quit(code); + }; +}); + +} + +if(env === 'xpconnect') { +/*global quit */ +define('xpconnect/quit', function () { + 'use strict'; + return function (code) { + return quit(code); + }; +}); + +} + +if(env === 'browser') { +/** + * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, console: false */ + +define('browser/print', function () { + function print(msg) { + console.log(msg); + } + + return print; +}); + +} + +if(env === 'node') { +/** + * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, console: false */ + +define('node/print', function () { + function print(msg) { + console.log(msg); + } + + return print; +}); + +} + +if(env === 'rhino') { +/** + * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, print: false */ + +define('rhino/print', function () { + return print; +}); + +} + +if(env === 'xpconnect') { +/** + * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false, print: false */ + +define('xpconnect/print', function () { + return print; +}); + +} +/** + * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint nomen: false, strict: false */ +/*global define: false */ + +define('logger', ['env!env/print'], function (print) { + var logger = { + TRACE: 0, + INFO: 1, + WARN: 2, + ERROR: 3, + SILENT: 4, + level: 0, + logPrefix: "", + + logLevel: function( level ) { + this.level = level; + }, + + trace: function (message) { + if (this.level <= this.TRACE) { + this._print(message); + } + }, + + info: function (message) { + if (this.level <= this.INFO) { + this._print(message); + } + }, + + warn: function (message) { + if (this.level <= this.WARN) { + this._print(message); + } + }, + + error: function (message) { + if (this.level <= this.ERROR) { + this._print(message); + } + }, + + _print: function (message) { + this._sysPrint((this.logPrefix ? (this.logPrefix + " ") : "") + message); + }, + + _sysPrint: function (message) { + print(message); + } + }; + + return logger; +}); +//Just a blank file to use when building the optimizer with the optimizer, +//so that the build does not attempt to inline some env modules, +//like Node's fs and path. + +/* + Copyright (C) 2012 Ariya Hidayat + Copyright (C) 2012 Mathias Bynens + Copyright (C) 2012 Joost-Wim Boekesteijn + Copyright (C) 2012 Kris Kowal + Copyright (C) 2012 Yusuke Suzuki + Copyright (C) 2012 Arpad Borsos + Copyright (C) 2011 Ariya Hidayat + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*jslint bitwise:true plusplus:true */ +/*global esprima:true, define:true, exports:true, window: true, +throwError: true, createLiteral: true, generateStatement: true, +parseAssignmentExpression: true, parseBlock: true, parseExpression: true, +parseFunctionDeclaration: true, parseFunctionExpression: true, +parseFunctionSourceElements: true, parseVariableIdentifier: true, +parseLeftHandSideExpression: true, +parseStatement: true, parseSourceElement: true */ + +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // Rhino, and plain browser loading. + if (typeof define === 'function' && define.amd) { + define('esprima', ['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.esprima = {})); + } +}(this, function (exports) { + 'use strict'; + + var Token, + TokenName, + Syntax, + PropertyKind, + Messages, + Regex, + source, + strict, + index, + lineNumber, + lineStart, + length, + buffer, + state, + extra; + + Token = { + BooleanLiteral: 1, + EOF: 2, + Identifier: 3, + Keyword: 4, + NullLiteral: 5, + NumericLiteral: 6, + Punctuator: 7, + StringLiteral: 8 + }; + + TokenName = {}; + TokenName[Token.BooleanLiteral] = 'Boolean'; + TokenName[Token.EOF] = ''; + TokenName[Token.Identifier] = 'Identifier'; + TokenName[Token.Keyword] = 'Keyword'; + TokenName[Token.NullLiteral] = 'Null'; + TokenName[Token.NumericLiteral] = 'Numeric'; + TokenName[Token.Punctuator] = 'Punctuator'; + TokenName[Token.StringLiteral] = 'String'; + + Syntax = { + AssignmentExpression: 'AssignmentExpression', + ArrayExpression: 'ArrayExpression', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DoWhileStatement: 'DoWhileStatement', + DebuggerStatement: 'DebuggerStatement', + EmptyStatement: 'EmptyStatement', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement' + }; + + PropertyKind = { + Data: 1, + Get: 2, + Set: 4 + }; + + // Error messages should be identical to V8. + Messages = { + UnexpectedToken: 'Unexpected token %0', + UnexpectedNumber: 'Unexpected number', + UnexpectedString: 'Unexpected string', + UnexpectedIdentifier: 'Unexpected identifier', + UnexpectedReserved: 'Unexpected reserved word', + UnexpectedEOS: 'Unexpected end of input', + NewlineAfterThrow: 'Illegal newline after throw', + InvalidRegExp: 'Invalid regular expression', + UnterminatedRegExp: 'Invalid regular expression: missing /', + InvalidLHSInAssignment: 'Invalid left-hand side in assignment', + InvalidLHSInForIn: 'Invalid left-hand side in for-in', + MultipleDefaultsInSwitch: 'More than one default clause in switch statement', + NoCatchOrFinally: 'Missing catch or finally after try', + UnknownLabel: 'Undefined label \'%0\'', + Redeclaration: '%0 \'%1\' has already been declared', + IllegalContinue: 'Illegal continue statement', + IllegalBreak: 'Illegal break statement', + IllegalReturn: 'Illegal return statement', + StrictModeWith: 'Strict mode code may not include a with statement', + StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', + StrictVarName: 'Variable name may not be eval or arguments in strict mode', + StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', + StrictParamDupe: 'Strict mode function may not have duplicate parameter names', + StrictFunctionName: 'Function name may not be eval or arguments in strict mode', + StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', + StrictDelete: 'Delete of an unqualified identifier in strict mode.', + StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', + AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', + AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', + StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', + StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', + StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', + StrictReservedWord: 'Use of future reserved word in strict mode' + }; + + // See also tools/generate-unicode-regex.py. + Regex = { + NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'), + NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]') + }; + + // Ensure the condition is true, otherwise throw an error. + // This is only to have a better contract semantic, i.e. another safety net + // to catch a logic error. The condition shall be fulfilled in normal case. + // Do NOT use this to enforce a certain condition on any user input. + + function assert(condition, message) { + if (!condition) { + throw new Error('ASSERT: ' + message); + } + } + + function sliceSource(from, to) { + return source.slice(from, to); + } + + if (typeof 'esprima'[0] === 'undefined') { + sliceSource = function sliceArraySource(from, to) { + return source.slice(from, to).join(''); + }; + } + + function isDecimalDigit(ch) { + return '0123456789'.indexOf(ch) >= 0; + } + + function isHexDigit(ch) { + return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; + } + + function isOctalDigit(ch) { + return '01234567'.indexOf(ch) >= 0; + } + + + // 7.2 White Space + + function isWhiteSpace(ch) { + return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') || + (ch === '\u000C') || (ch === '\u00A0') || + (ch.charCodeAt(0) >= 0x1680 && + '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0); + } + + // 7.3 Line Terminators + + function isLineTerminator(ch) { + return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029'); + } + + // 7.6 Identifier Names and Identifiers + + function isIdentifierStart(ch) { + return (ch === '$') || (ch === '_') || (ch === '\\') || + (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || + ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch)); + } + + function isIdentifierPart(ch) { + return (ch === '$') || (ch === '_') || (ch === '\\') || + (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || + ((ch >= '0') && (ch <= '9')) || + ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch)); + } + + // 7.6.1.2 Future Reserved Words + + function isFutureReservedWord(id) { + switch (id) { + + // Future reserved words. + case 'class': + case 'enum': + case 'export': + case 'extends': + case 'import': + case 'super': + return true; + } + + return false; + } + + function isStrictModeReservedWord(id) { + switch (id) { + + // Strict Mode reserved words. + case 'implements': + case 'interface': + case 'package': + case 'private': + case 'protected': + case 'public': + case 'static': + case 'yield': + case 'let': + return true; + } + + return false; + } + + function isRestrictedWord(id) { + return id === 'eval' || id === 'arguments'; + } + + // 7.6.1.1 Keywords + + function isKeyword(id) { + var keyword = false; + switch (id.length) { + case 2: + keyword = (id === 'if') || (id === 'in') || (id === 'do'); + break; + case 3: + keyword = (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try'); + break; + case 4: + keyword = (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with'); + break; + case 5: + keyword = (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw'); + break; + case 6: + keyword = (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch'); + break; + case 7: + keyword = (id === 'default') || (id === 'finally'); + break; + case 8: + keyword = (id === 'function') || (id === 'continue') || (id === 'debugger'); + break; + case 10: + keyword = (id === 'instanceof'); + break; + } + + if (keyword) { + return true; + } + + switch (id) { + // Future reserved words. + // 'const' is specialized as Keyword in V8. + case 'const': + return true; + + // For compatiblity to SpiderMonkey and ES.next + case 'yield': + case 'let': + return true; + } + + if (strict && isStrictModeReservedWord(id)) { + return true; + } + + return isFutureReservedWord(id); + } + + // 7.4 Comments + + function skipComment() { + var ch, blockComment, lineComment; + + blockComment = false; + lineComment = false; + + while (index < length) { + ch = source[index]; + + if (lineComment) { + ch = source[index++]; + if (isLineTerminator(ch)) { + lineComment = false; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + } + } else if (blockComment) { + if (isLineTerminator(ch)) { + if (ch === '\r' && source[index + 1] === '\n') { + ++index; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + ch = source[index++]; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + if (ch === '*') { + ch = source[index]; + if (ch === '/') { + ++index; + blockComment = false; + } + } + } + } else if (ch === '/') { + ch = source[index + 1]; + if (ch === '/') { + index += 2; + lineComment = true; + } else if (ch === '*') { + index += 2; + blockComment = true; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + break; + } + } else if (isWhiteSpace(ch)) { + ++index; + } else if (isLineTerminator(ch)) { + ++index; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + } else { + break; + } + } + } + + function scanHexEscape(prefix) { + var i, len, ch, code = 0; + + len = (prefix === 'u') ? 4 : 2; + for (i = 0; i < len; ++i) { + if (index < length && isHexDigit(source[index])) { + ch = source[index++]; + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } else { + return ''; + } + } + return String.fromCharCode(code); + } + + function scanIdentifier() { + var ch, start, id, restore; + + ch = source[index]; + if (!isIdentifierStart(ch)) { + return; + } + + start = index; + if (ch === '\\') { + ++index; + if (source[index] !== 'u') { + return; + } + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + if (ch === '\\' || !isIdentifierStart(ch)) { + return; + } + id = ch; + } else { + index = restore; + id = 'u'; + } + } else { + id = source[index++]; + } + + while (index < length) { + ch = source[index]; + if (!isIdentifierPart(ch)) { + break; + } + if (ch === '\\') { + ++index; + if (source[index] !== 'u') { + return; + } + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + if (ch === '\\' || !isIdentifierPart(ch)) { + return; + } + id += ch; + } else { + index = restore; + id += 'u'; + } + } else { + id += source[index++]; + } + } + + // There is no keyword or literal with only one character. + // Thus, it must be an identifier. + if (id.length === 1) { + return { + type: Token.Identifier, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (isKeyword(id)) { + return { + type: Token.Keyword, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // 7.8.1 Null Literals + + if (id === 'null') { + return { + type: Token.NullLiteral, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // 7.8.2 Boolean Literals + + if (id === 'true' || id === 'false') { + return { + type: Token.BooleanLiteral, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + return { + type: Token.Identifier, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // 7.7 Punctuators + + function scanPunctuator() { + var start = index, + ch1 = source[index], + ch2, + ch3, + ch4; + + // Check for most common single-character punctuators. + + if (ch1 === ';' || ch1 === '{' || ch1 === '}') { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === ',' || ch1 === '(' || ch1 === ')') { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // Dot (.) can also start a floating-point number, hence the need + // to check the next character. + + ch2 = source[index + 1]; + if (ch1 === '.' && !isDecimalDigit(ch2)) { + return { + type: Token.Punctuator, + value: source[index++], + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // Peek more characters. + + ch3 = source[index + 2]; + ch4 = source[index + 3]; + + // 4-character punctuator: >>>= + + if (ch1 === '>' && ch2 === '>' && ch3 === '>') { + if (ch4 === '=') { + index += 4; + return { + type: Token.Punctuator, + value: '>>>=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + } + + // 3-character punctuators: === !== >>> <<= >>= + + if (ch1 === '=' && ch2 === '=' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '===', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '!' && ch2 === '=' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '!==', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '>' && ch2 === '>' && ch3 === '>') { + index += 3; + return { + type: Token.Punctuator, + value: '>>>', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '<' && ch2 === '<' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '<<=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '>' && ch2 === '>' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '>>=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // 2-character punctuators: <= >= == != ++ -- << >> && || + // += -= *= %= &= |= ^= /= + + if (ch2 === '=') { + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { + index += 2; + return { + type: Token.Punctuator, + value: ch1 + ch2, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + } + + if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) { + if ('+-<>&|'.indexOf(ch2) >= 0) { + index += 2; + return { + type: Token.Punctuator, + value: ch1 + ch2, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + } + + // The remaining 1-character punctuators. + + if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) { + return { + type: Token.Punctuator, + value: source[index++], + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + } + + // 7.8.3 Numeric Literals + + function scanNumericLiteral() { + var number, start, ch; + + ch = source[index]; + assert(isDecimalDigit(ch) || (ch === '.'), + 'Numeric literal must start with a decimal digit or a decimal point'); + + start = index; + number = ''; + if (ch !== '.') { + number = source[index++]; + ch = source[index]; + + // Hex number starts with '0x'. + // Octal number starts with '0'. + if (number === '0') { + if (ch === 'x' || ch === 'X') { + number += source[index++]; + while (index < length) { + ch = source[index]; + if (!isHexDigit(ch)) { + break; + } + number += source[index++]; + } + + if (number.length <= 2) { + // only 0x + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (index < length) { + ch = source[index]; + if (isIdentifierStart(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + return { + type: Token.NumericLiteral, + value: parseInt(number, 16), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } else if (isOctalDigit(ch)) { + number += source[index++]; + while (index < length) { + ch = source[index]; + if (!isOctalDigit(ch)) { + break; + } + number += source[index++]; + } + + if (index < length) { + ch = source[index]; + if (isIdentifierStart(ch) || isDecimalDigit(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + return { + type: Token.NumericLiteral, + value: parseInt(number, 8), + octal: true, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // decimal number starts with '0' such as '09' is illegal. + if (isDecimalDigit(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + while (index < length) { + ch = source[index]; + if (!isDecimalDigit(ch)) { + break; + } + number += source[index++]; + } + } + + if (ch === '.') { + number += source[index++]; + while (index < length) { + ch = source[index]; + if (!isDecimalDigit(ch)) { + break; + } + number += source[index++]; + } + } + + if (ch === 'e' || ch === 'E') { + number += source[index++]; + + ch = source[index]; + if (ch === '+' || ch === '-') { + number += source[index++]; + } + + ch = source[index]; + if (isDecimalDigit(ch)) { + number += source[index++]; + while (index < length) { + ch = source[index]; + if (!isDecimalDigit(ch)) { + break; + } + number += source[index++]; + } + } else { + ch = 'character ' + ch; + if (index >= length) { + ch = ''; + } + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + if (index < length) { + ch = source[index]; + if (isIdentifierStart(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + return { + type: Token.NumericLiteral, + value: parseFloat(number), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // 7.8.4 String Literals + + function scanStringLiteral() { + var str = '', quote, start, ch, code, unescaped, restore, octal = false; + + quote = source[index]; + assert((quote === '\'' || quote === '"'), + 'String literal must starts with a quote'); + + start = index; + ++index; + + while (index < length) { + ch = source[index++]; + + if (ch === quote) { + quote = ''; + break; + } else if (ch === '\\') { + ch = source[index++]; + if (!isLineTerminator(ch)) { + switch (ch) { + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'u': + case 'x': + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + str += unescaped; + } else { + index = restore; + str += ch; + } + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case 'v': + str += '\x0B'; + break; + + default: + if (isOctalDigit(ch)) { + code = '01234567'.indexOf(ch); + + // \0 is not octal escape sequence + if (code !== 0) { + octal = true; + } + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + str += String.fromCharCode(code); + } else { + str += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + } + } else if (isLineTerminator(ch)) { + break; + } else { + str += ch; + } + } + + if (quote !== '') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.StringLiteral, + value: str, + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanRegExp() { + var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false; + + buffer = null; + skipComment(); + + start = index; + ch = source[index]; + assert(ch === '/', 'Regular expression literal must start with a slash'); + str = source[index++]; + + while (index < length) { + ch = source[index++]; + str += ch; + if (ch === '\\') { + ch = source[index++]; + // ECMA-262 7.8.5 + if (isLineTerminator(ch)) { + throwError({}, Messages.UnterminatedRegExp); + } + str += ch; + } else if (classMarker) { + if (ch === ']') { + classMarker = false; + } + } else { + if (ch === '/') { + terminated = true; + break; + } else if (ch === '[') { + classMarker = true; + } else if (isLineTerminator(ch)) { + throwError({}, Messages.UnterminatedRegExp); + } + } + } + + if (!terminated) { + throwError({}, Messages.UnterminatedRegExp); + } + + // Exclude leading and trailing slash. + pattern = str.substr(1, str.length - 2); + + flags = ''; + while (index < length) { + ch = source[index]; + if (!isIdentifierPart(ch)) { + break; + } + + ++index; + if (ch === '\\' && index < length) { + ch = source[index]; + if (ch === 'u') { + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + flags += ch; + str += '\\u'; + for (; restore < index; ++restore) { + str += source[restore]; + } + } else { + index = restore; + flags += 'u'; + str += '\\u'; + } + } else { + str += '\\'; + } + } else { + flags += ch; + str += ch; + } + } + + try { + value = new RegExp(pattern, flags); + } catch (e) { + throwError({}, Messages.InvalidRegExp); + } + + return { + literal: str, + value: value, + range: [start, index] + }; + } + + function isIdentifierName(token) { + return token.type === Token.Identifier || + token.type === Token.Keyword || + token.type === Token.BooleanLiteral || + token.type === Token.NullLiteral; + } + + function advance() { + var ch, token; + + skipComment(); + + if (index >= length) { + return { + type: Token.EOF, + lineNumber: lineNumber, + lineStart: lineStart, + range: [index, index] + }; + } + + token = scanPunctuator(); + if (typeof token !== 'undefined') { + return token; + } + + ch = source[index]; + + if (ch === '\'' || ch === '"') { + return scanStringLiteral(); + } + + if (ch === '.' || isDecimalDigit(ch)) { + return scanNumericLiteral(); + } + + token = scanIdentifier(); + if (typeof token !== 'undefined') { + return token; + } + + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + function lex() { + var token; + + if (buffer) { + index = buffer.range[1]; + lineNumber = buffer.lineNumber; + lineStart = buffer.lineStart; + token = buffer; + buffer = null; + return token; + } + + buffer = null; + return advance(); + } + + function lookahead() { + var pos, line, start; + + if (buffer !== null) { + return buffer; + } + + pos = index; + line = lineNumber; + start = lineStart; + buffer = advance(); + index = pos; + lineNumber = line; + lineStart = start; + + return buffer; + } + + // Return true if there is a line terminator before the next token. + + function peekLineTerminator() { + var pos, line, start, found; + + pos = index; + line = lineNumber; + start = lineStart; + skipComment(); + found = lineNumber !== line; + index = pos; + lineNumber = line; + lineStart = start; + + return found; + } + + // Throw an exception + + function throwError(token, messageFormat) { + var error, + args = Array.prototype.slice.call(arguments, 2), + msg = messageFormat.replace( + /%(\d)/g, + function (whole, index) { + return args[index] || ''; + } + ); + + if (typeof token.lineNumber === 'number') { + error = new Error('Line ' + token.lineNumber + ': ' + msg); + error.index = token.range[0]; + error.lineNumber = token.lineNumber; + error.column = token.range[0] - lineStart + 1; + } else { + error = new Error('Line ' + lineNumber + ': ' + msg); + error.index = index; + error.lineNumber = lineNumber; + error.column = index - lineStart + 1; + } + + throw error; + } + + function throwErrorTolerant() { + try { + throwError.apply(null, arguments); + } catch (e) { + if (extra.errors) { + extra.errors.push(e); + } else { + throw e; + } + } + } + + + // Throw an exception because of the token. + + function throwUnexpected(token) { + if (token.type === Token.EOF) { + throwError(token, Messages.UnexpectedEOS); + } + + if (token.type === Token.NumericLiteral) { + throwError(token, Messages.UnexpectedNumber); + } + + if (token.type === Token.StringLiteral) { + throwError(token, Messages.UnexpectedString); + } + + if (token.type === Token.Identifier) { + throwError(token, Messages.UnexpectedIdentifier); + } + + if (token.type === Token.Keyword) { + if (isFutureReservedWord(token.value)) { + throwError(token, Messages.UnexpectedReserved); + } else if (strict && isStrictModeReservedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictReservedWord); + return; + } + throwError(token, Messages.UnexpectedToken, token.value); + } + + // BooleanLiteral, NullLiteral, or Punctuator. + throwError(token, Messages.UnexpectedToken, token.value); + } + + // Expect the next token to match the specified punctuator. + // If not, an exception will be thrown. + + function expect(value) { + var token = lex(); + if (token.type !== Token.Punctuator || token.value !== value) { + throwUnexpected(token); + } + } + + // Expect the next token to match the specified keyword. + // If not, an exception will be thrown. + + function expectKeyword(keyword) { + var token = lex(); + if (token.type !== Token.Keyword || token.value !== keyword) { + throwUnexpected(token); + } + } + + // Return true if the next token matches the specified punctuator. + + function match(value) { + var token = lookahead(); + return token.type === Token.Punctuator && token.value === value; + } + + // Return true if the next token matches the specified keyword + + function matchKeyword(keyword) { + var token = lookahead(); + return token.type === Token.Keyword && token.value === keyword; + } + + // Return true if the next token is an assignment operator + + function matchAssign() { + var token = lookahead(), + op = token.value; + + if (token.type !== Token.Punctuator) { + return false; + } + return op === '=' || + op === '*=' || + op === '/=' || + op === '%=' || + op === '+=' || + op === '-=' || + op === '<<=' || + op === '>>=' || + op === '>>>=' || + op === '&=' || + op === '^=' || + op === '|='; + } + + function consumeSemicolon() { + var token, line; + + // Catch the very common case first. + if (source[index] === ';') { + lex(); + return; + } + + line = lineNumber; + skipComment(); + if (lineNumber !== line) { + return; + } + + if (match(';')) { + lex(); + return; + } + + token = lookahead(); + if (token.type !== Token.EOF && !match('}')) { + throwUnexpected(token); + } + } + + // Return true if provided expression is LeftHandSideExpression + + function isLeftHandSide(expr) { + return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression; + } + + // 11.1.4 Array Initialiser + + function parseArrayInitialiser() { + var elements = []; + + expect('['); + + while (!match(']')) { + if (match(',')) { + lex(); + elements.push(null); + } else { + elements.push(parseAssignmentExpression()); + + if (!match(']')) { + expect(','); + } + } + } + + expect(']'); + + return { + type: Syntax.ArrayExpression, + elements: elements + }; + } + + // 11.1.5 Object Initialiser + + function parsePropertyFunction(param, first) { + var previousStrict, body; + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (first && strict && isRestrictedWord(param[0].name)) { + throwErrorTolerant(first, Messages.StrictParamName); + } + strict = previousStrict; + + return { + type: Syntax.FunctionExpression, + id: null, + params: param, + defaults: [], + body: body, + rest: null, + generator: false, + expression: false + }; + } + + function parseObjectPropertyKey() { + var token = lex(); + + // Note: This function is called only from parseObjectProperty(), where + // EOF and Punctuator tokens are already filtered out. + + if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { + if (strict && token.octal) { + throwErrorTolerant(token, Messages.StrictOctalLiteral); + } + return createLiteral(token); + } + + return { + type: Syntax.Identifier, + name: token.value + }; + } + + function parseObjectProperty() { + var token, key, id, param; + + token = lookahead(); + + if (token.type === Token.Identifier) { + + id = parseObjectPropertyKey(); + + // Property Assignment: Getter and Setter. + + if (token.value === 'get' && !match(':')) { + key = parseObjectPropertyKey(); + expect('('); + expect(')'); + return { + type: Syntax.Property, + key: key, + value: parsePropertyFunction([]), + kind: 'get' + }; + } else if (token.value === 'set' && !match(':')) { + key = parseObjectPropertyKey(); + expect('('); + token = lookahead(); + if (token.type !== Token.Identifier) { + expect(')'); + throwErrorTolerant(token, Messages.UnexpectedToken, token.value); + return { + type: Syntax.Property, + key: key, + value: parsePropertyFunction([]), + kind: 'set' + }; + } else { + param = [ parseVariableIdentifier() ]; + expect(')'); + return { + type: Syntax.Property, + key: key, + value: parsePropertyFunction(param, token), + kind: 'set' + }; + } + } else { + expect(':'); + return { + type: Syntax.Property, + key: id, + value: parseAssignmentExpression(), + kind: 'init' + }; + } + } else if (token.type === Token.EOF || token.type === Token.Punctuator) { + throwUnexpected(token); + } else { + key = parseObjectPropertyKey(); + expect(':'); + return { + type: Syntax.Property, + key: key, + value: parseAssignmentExpression(), + kind: 'init' + }; + } + } + + function parseObjectInitialiser() { + var properties = [], property, name, kind, map = {}, toString = String; + + expect('{'); + + while (!match('}')) { + property = parseObjectProperty(); + + if (property.key.type === Syntax.Identifier) { + name = property.key.name; + } else { + name = toString(property.key.value); + } + kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; + if (Object.prototype.hasOwnProperty.call(map, name)) { + if (map[name] === PropertyKind.Data) { + if (strict && kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.StrictDuplicateProperty); + } else if (kind !== PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } + } else { + if (kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } else if (map[name] & kind) { + throwErrorTolerant({}, Messages.AccessorGetSet); + } + } + map[name] |= kind; + } else { + map[name] = kind; + } + + properties.push(property); + + if (!match('}')) { + expect(','); + } + } + + expect('}'); + + return { + type: Syntax.ObjectExpression, + properties: properties + }; + } + + // 11.1.6 The Grouping Operator + + function parseGroupExpression() { + var expr; + + expect('('); + + expr = parseExpression(); + + expect(')'); + + return expr; + } + + + // 11.1 Primary Expressions + + function parsePrimaryExpression() { + var token = lookahead(), + type = token.type; + + if (type === Token.Identifier) { + return { + type: Syntax.Identifier, + name: lex().value + }; + } + + if (type === Token.StringLiteral || type === Token.NumericLiteral) { + if (strict && token.octal) { + throwErrorTolerant(token, Messages.StrictOctalLiteral); + } + return createLiteral(lex()); + } + + if (type === Token.Keyword) { + if (matchKeyword('this')) { + lex(); + return { + type: Syntax.ThisExpression + }; + } + + if (matchKeyword('function')) { + return parseFunctionExpression(); + } + } + + if (type === Token.BooleanLiteral) { + lex(); + token.value = (token.value === 'true'); + return createLiteral(token); + } + + if (type === Token.NullLiteral) { + lex(); + token.value = null; + return createLiteral(token); + } + + if (match('[')) { + return parseArrayInitialiser(); + } + + if (match('{')) { + return parseObjectInitialiser(); + } + + if (match('(')) { + return parseGroupExpression(); + } + + if (match('/') || match('/=')) { + return createLiteral(scanRegExp()); + } + + return throwUnexpected(lex()); + } + + // 11.2 Left-Hand-Side Expressions + + function parseArguments() { + var args = []; + + expect('('); + + if (!match(')')) { + while (index < length) { + args.push(parseAssignmentExpression()); + if (match(')')) { + break; + } + expect(','); + } + } + + expect(')'); + + return args; + } + + function parseNonComputedProperty() { + var token = lex(); + + if (!isIdentifierName(token)) { + throwUnexpected(token); + } + + return { + type: Syntax.Identifier, + name: token.value + }; + } + + function parseNonComputedMember() { + expect('.'); + + return parseNonComputedProperty(); + } + + function parseComputedMember() { + var expr; + + expect('['); + + expr = parseExpression(); + + expect(']'); + + return expr; + } + + function parseNewExpression() { + var expr; + + expectKeyword('new'); + + expr = { + type: Syntax.NewExpression, + callee: parseLeftHandSideExpression(), + 'arguments': [] + }; + + if (match('(')) { + expr['arguments'] = parseArguments(); + } + + return expr; + } + + function parseLeftHandSideExpressionAllowCall() { + var expr; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || match('(')) { + if (match('(')) { + expr = { + type: Syntax.CallExpression, + callee: expr, + 'arguments': parseArguments() + }; + } else if (match('[')) { + expr = { + type: Syntax.MemberExpression, + computed: true, + object: expr, + property: parseComputedMember() + }; + } else { + expr = { + type: Syntax.MemberExpression, + computed: false, + object: expr, + property: parseNonComputedMember() + }; + } + } + + return expr; + } + + + function parseLeftHandSideExpression() { + var expr; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[')) { + if (match('[')) { + expr = { + type: Syntax.MemberExpression, + computed: true, + object: expr, + property: parseComputedMember() + }; + } else { + expr = { + type: Syntax.MemberExpression, + computed: false, + object: expr, + property: parseNonComputedMember() + }; + } + } + + return expr; + } + + // 11.3 Postfix Expressions + + function parsePostfixExpression() { + var expr = parseLeftHandSideExpressionAllowCall(), token; + + token = lookahead(); + if (token.type !== Token.Punctuator) { + return expr; + } + + if ((match('++') || match('--')) && !peekLineTerminator()) { + // 11.3.1, 11.3.2 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPostfix); + } + if (!isLeftHandSide(expr)) { + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + } + + expr = { + type: Syntax.UpdateExpression, + operator: lex().value, + argument: expr, + prefix: false + }; + } + + return expr; + } + + // 11.4 Unary Operators + + function parseUnaryExpression() { + var token, expr; + + token = lookahead(); + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { + return parsePostfixExpression(); + } + + if (match('++') || match('--')) { + token = lex(); + expr = parseUnaryExpression(); + // 11.4.4, 11.4.5 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPrefix); + } + + if (!isLeftHandSide(expr)) { + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + } + + expr = { + type: Syntax.UpdateExpression, + operator: token.value, + argument: expr, + prefix: true + }; + return expr; + } + + if (match('+') || match('-') || match('~') || match('!')) { + expr = { + type: Syntax.UnaryExpression, + operator: lex().value, + argument: parseUnaryExpression(), + prefix: true + }; + return expr; + } + + if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { + expr = { + type: Syntax.UnaryExpression, + operator: lex().value, + argument: parseUnaryExpression(), + prefix: true + }; + if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { + throwErrorTolerant({}, Messages.StrictDelete); + } + return expr; + } + + return parsePostfixExpression(); + } + + // 11.5 Multiplicative Operators + + function parseMultiplicativeExpression() { + var expr = parseUnaryExpression(); + + while (match('*') || match('/') || match('%')) { + expr = { + type: Syntax.BinaryExpression, + operator: lex().value, + left: expr, + right: parseUnaryExpression() + }; + } + + return expr; + } + + // 11.6 Additive Operators + + function parseAdditiveExpression() { + var expr = parseMultiplicativeExpression(); + + while (match('+') || match('-')) { + expr = { + type: Syntax.BinaryExpression, + operator: lex().value, + left: expr, + right: parseMultiplicativeExpression() + }; + } + + return expr; + } + + // 11.7 Bitwise Shift Operators + + function parseShiftExpression() { + var expr = parseAdditiveExpression(); + + while (match('<<') || match('>>') || match('>>>')) { + expr = { + type: Syntax.BinaryExpression, + operator: lex().value, + left: expr, + right: parseAdditiveExpression() + }; + } + + return expr; + } + // 11.8 Relational Operators + + function parseRelationalExpression() { + var expr, previousAllowIn; + + previousAllowIn = state.allowIn; + state.allowIn = true; + + expr = parseShiftExpression(); + + while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) { + expr = { + type: Syntax.BinaryExpression, + operator: lex().value, + left: expr, + right: parseShiftExpression() + }; + } + + state.allowIn = previousAllowIn; + return expr; + } + + // 11.9 Equality Operators + + function parseEqualityExpression() { + var expr = parseRelationalExpression(); + + while (match('==') || match('!=') || match('===') || match('!==')) { + expr = { + type: Syntax.BinaryExpression, + operator: lex().value, + left: expr, + right: parseRelationalExpression() + }; + } + + return expr; + } + + // 11.10 Binary Bitwise Operators + + function parseBitwiseANDExpression() { + var expr = parseEqualityExpression(); + + while (match('&')) { + lex(); + expr = { + type: Syntax.BinaryExpression, + operator: '&', + left: expr, + right: parseEqualityExpression() + }; + } + + return expr; + } + + function parseBitwiseXORExpression() { + var expr = parseBitwiseANDExpression(); + + while (match('^')) { + lex(); + expr = { + type: Syntax.BinaryExpression, + operator: '^', + left: expr, + right: parseBitwiseANDExpression() + }; + } + + return expr; + } + + function parseBitwiseORExpression() { + var expr = parseBitwiseXORExpression(); + + while (match('|')) { + lex(); + expr = { + type: Syntax.BinaryExpression, + operator: '|', + left: expr, + right: parseBitwiseXORExpression() + }; + } + + return expr; + } + + // 11.11 Binary Logical Operators + + function parseLogicalANDExpression() { + var expr = parseBitwiseORExpression(); + + while (match('&&')) { + lex(); + expr = { + type: Syntax.LogicalExpression, + operator: '&&', + left: expr, + right: parseBitwiseORExpression() + }; + } + + return expr; + } + + function parseLogicalORExpression() { + var expr = parseLogicalANDExpression(); + + while (match('||')) { + lex(); + expr = { + type: Syntax.LogicalExpression, + operator: '||', + left: expr, + right: parseLogicalANDExpression() + }; + } + + return expr; + } + + // 11.12 Conditional Operator + + function parseConditionalExpression() { + var expr, previousAllowIn, consequent; + + expr = parseLogicalORExpression(); + + if (match('?')) { + lex(); + previousAllowIn = state.allowIn; + state.allowIn = true; + consequent = parseAssignmentExpression(); + state.allowIn = previousAllowIn; + expect(':'); + + expr = { + type: Syntax.ConditionalExpression, + test: expr, + consequent: consequent, + alternate: parseAssignmentExpression() + }; + } + + return expr; + } + + // 11.13 Assignment Operators + + function parseAssignmentExpression() { + var token, expr; + + token = lookahead(); + expr = parseConditionalExpression(); + + if (matchAssign()) { + // LeftHandSideExpression + if (!isLeftHandSide(expr)) { + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + } + + // 11.13.1 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant(token, Messages.StrictLHSAssignment); + } + + expr = { + type: Syntax.AssignmentExpression, + operator: lex().value, + left: expr, + right: parseAssignmentExpression() + }; + } + + return expr; + } + + // 11.14 Comma Operator + + function parseExpression() { + var expr = parseAssignmentExpression(); + + if (match(',')) { + expr = { + type: Syntax.SequenceExpression, + expressions: [ expr ] + }; + + while (index < length) { + if (!match(',')) { + break; + } + lex(); + expr.expressions.push(parseAssignmentExpression()); + } + + } + return expr; + } + + // 12.1 Block + + function parseStatementList() { + var list = [], + statement; + + while (index < length) { + if (match('}')) { + break; + } + statement = parseSourceElement(); + if (typeof statement === 'undefined') { + break; + } + list.push(statement); + } + + return list; + } + + function parseBlock() { + var block; + + expect('{'); + + block = parseStatementList(); + + expect('}'); + + return { + type: Syntax.BlockStatement, + body: block + }; + } + + // 12.2 Variable Statement + + function parseVariableIdentifier() { + var token = lex(); + + if (token.type !== Token.Identifier) { + throwUnexpected(token); + } + + return { + type: Syntax.Identifier, + name: token.value + }; + } + + function parseVariableDeclaration(kind) { + var id = parseVariableIdentifier(), + init = null; + + // 12.2.1 + if (strict && isRestrictedWord(id.name)) { + throwErrorTolerant({}, Messages.StrictVarName); + } + + if (kind === 'const') { + expect('='); + init = parseAssignmentExpression(); + } else if (match('=')) { + lex(); + init = parseAssignmentExpression(); + } + + return { + type: Syntax.VariableDeclarator, + id: id, + init: init + }; + } + + function parseVariableDeclarationList(kind) { + var list = []; + + do { + list.push(parseVariableDeclaration(kind)); + if (!match(',')) { + break; + } + lex(); + } while (index < length); + + return list; + } + + function parseVariableStatement() { + var declarations; + + expectKeyword('var'); + + declarations = parseVariableDeclarationList(); + + consumeSemicolon(); + + return { + type: Syntax.VariableDeclaration, + declarations: declarations, + kind: 'var' + }; + } + + // kind may be `const` or `let` + // Both are experimental and not in the specification yet. + // see http://wiki.ecmascript.org/doku.php?id=harmony:const + // and http://wiki.ecmascript.org/doku.php?id=harmony:let + function parseConstLetDeclaration(kind) { + var declarations; + + expectKeyword(kind); + + declarations = parseVariableDeclarationList(kind); + + consumeSemicolon(); + + return { + type: Syntax.VariableDeclaration, + declarations: declarations, + kind: kind + }; + } + + // 12.3 Empty Statement + + function parseEmptyStatement() { + expect(';'); + + return { + type: Syntax.EmptyStatement + }; + } + + // 12.4 Expression Statement + + function parseExpressionStatement() { + var expr = parseExpression(); + + consumeSemicolon(); + + return { + type: Syntax.ExpressionStatement, + expression: expr + }; + } + + // 12.5 If statement + + function parseIfStatement() { + var test, consequent, alternate; + + expectKeyword('if'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + consequent = parseStatement(); + + if (matchKeyword('else')) { + lex(); + alternate = parseStatement(); + } else { + alternate = null; + } + + return { + type: Syntax.IfStatement, + test: test, + consequent: consequent, + alternate: alternate + }; + } + + // 12.6 Iteration Statements + + function parseDoWhileStatement() { + var body, test, oldInIteration; + + expectKeyword('do'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + if (match(';')) { + lex(); + } + + return { + type: Syntax.DoWhileStatement, + body: body, + test: test + }; + } + + function parseWhileStatement() { + var test, body, oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return { + type: Syntax.WhileStatement, + test: test, + body: body + }; + } + + function parseForVariableDeclaration() { + var token = lex(); + + return { + type: Syntax.VariableDeclaration, + declarations: parseVariableDeclarationList(), + kind: token.value + }; + } + + function parseForStatement() { + var init, test, update, left, right, body, oldInIteration; + + init = test = update = null; + + expectKeyword('for'); + + expect('('); + + if (match(';')) { + lex(); + } else { + if (matchKeyword('var') || matchKeyword('let')) { + state.allowIn = false; + init = parseForVariableDeclaration(); + state.allowIn = true; + + if (init.declarations.length === 1 && matchKeyword('in')) { + lex(); + left = init; + right = parseExpression(); + init = null; + } + } else { + state.allowIn = false; + init = parseExpression(); + state.allowIn = true; + + if (matchKeyword('in')) { + // LeftHandSideExpression + if (!isLeftHandSide(init)) { + throwErrorTolerant({}, Messages.InvalidLHSInForIn); + } + + lex(); + left = init; + right = parseExpression(); + init = null; + } + } + + if (typeof left === 'undefined') { + expect(';'); + } + } + + if (typeof left === 'undefined') { + + if (!match(';')) { + test = parseExpression(); + } + expect(';'); + + if (!match(')')) { + update = parseExpression(); + } + } + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + if (typeof left === 'undefined') { + return { + type: Syntax.ForStatement, + init: init, + test: test, + update: update, + body: body + }; + } + + return { + type: Syntax.ForInStatement, + left: left, + right: right, + body: body, + each: false + }; + } + + // 12.7 The continue statement + + function parseContinueStatement() { + var token, label = null; + + expectKeyword('continue'); + + // Optimize the most common form: 'continue;'. + if (source[index] === ';') { + lex(); + + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return { + type: Syntax.ContinueStatement, + label: null + }; + } + + if (peekLineTerminator()) { + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return { + type: Syntax.ContinueStatement, + label: null + }; + } + + token = lookahead(); + if (token.type === Token.Identifier) { + label = parseVariableIdentifier(); + + if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return { + type: Syntax.ContinueStatement, + label: label + }; + } + + // 12.8 The break statement + + function parseBreakStatement() { + var token, label = null; + + expectKeyword('break'); + + // Optimize the most common form: 'break;'. + if (source[index] === ';') { + lex(); + + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return { + type: Syntax.BreakStatement, + label: null + }; + } + + if (peekLineTerminator()) { + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return { + type: Syntax.BreakStatement, + label: null + }; + } + + token = lookahead(); + if (token.type === Token.Identifier) { + label = parseVariableIdentifier(); + + if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return { + type: Syntax.BreakStatement, + label: label + }; + } + + // 12.9 The return statement + + function parseReturnStatement() { + var token, argument = null; + + expectKeyword('return'); + + if (!state.inFunctionBody) { + throwErrorTolerant({}, Messages.IllegalReturn); + } + + // 'return' followed by a space and an identifier is very common. + if (source[index] === ' ') { + if (isIdentifierStart(source[index + 1])) { + argument = parseExpression(); + consumeSemicolon(); + return { + type: Syntax.ReturnStatement, + argument: argument + }; + } + } + + if (peekLineTerminator()) { + return { + type: Syntax.ReturnStatement, + argument: null + }; + } + + if (!match(';')) { + token = lookahead(); + if (!match('}') && token.type !== Token.EOF) { + argument = parseExpression(); + } + } + + consumeSemicolon(); + + return { + type: Syntax.ReturnStatement, + argument: argument + }; + } + + // 12.10 The with statement + + function parseWithStatement() { + var object, body; + + if (strict) { + throwErrorTolerant({}, Messages.StrictModeWith); + } + + expectKeyword('with'); + + expect('('); + + object = parseExpression(); + + expect(')'); + + body = parseStatement(); + + return { + type: Syntax.WithStatement, + object: object, + body: body + }; + } + + // 12.10 The swith statement + + function parseSwitchCase() { + var test, + consequent = [], + statement; + + if (matchKeyword('default')) { + lex(); + test = null; + } else { + expectKeyword('case'); + test = parseExpression(); + } + expect(':'); + + while (index < length) { + if (match('}') || matchKeyword('default') || matchKeyword('case')) { + break; + } + statement = parseStatement(); + if (typeof statement === 'undefined') { + break; + } + consequent.push(statement); + } + + return { + type: Syntax.SwitchCase, + test: test, + consequent: consequent + }; + } + + function parseSwitchStatement() { + var discriminant, cases, clause, oldInSwitch, defaultFound; + + expectKeyword('switch'); + + expect('('); + + discriminant = parseExpression(); + + expect(')'); + + expect('{'); + + cases = []; + + if (match('}')) { + lex(); + return { + type: Syntax.SwitchStatement, + discriminant: discriminant, + cases: cases + }; + } + + oldInSwitch = state.inSwitch; + state.inSwitch = true; + defaultFound = false; + + while (index < length) { + if (match('}')) { + break; + } + clause = parseSwitchCase(); + if (clause.test === null) { + if (defaultFound) { + throwError({}, Messages.MultipleDefaultsInSwitch); + } + defaultFound = true; + } + cases.push(clause); + } + + state.inSwitch = oldInSwitch; + + expect('}'); + + return { + type: Syntax.SwitchStatement, + discriminant: discriminant, + cases: cases + }; + } + + // 12.13 The throw statement + + function parseThrowStatement() { + var argument; + + expectKeyword('throw'); + + if (peekLineTerminator()) { + throwError({}, Messages.NewlineAfterThrow); + } + + argument = parseExpression(); + + consumeSemicolon(); + + return { + type: Syntax.ThrowStatement, + argument: argument + }; + } + + // 12.14 The try statement + + function parseCatchClause() { + var param; + + expectKeyword('catch'); + + expect('('); + if (match(')')) { + throwUnexpected(lookahead()); + } + + param = parseVariableIdentifier(); + // 12.14.1 + if (strict && isRestrictedWord(param.name)) { + throwErrorTolerant({}, Messages.StrictCatchVariable); + } + + expect(')'); + + return { + type: Syntax.CatchClause, + param: param, + body: parseBlock() + }; + } + + function parseTryStatement() { + var block, handlers = [], finalizer = null; + + expectKeyword('try'); + + block = parseBlock(); + + if (matchKeyword('catch')) { + handlers.push(parseCatchClause()); + } + + if (matchKeyword('finally')) { + lex(); + finalizer = parseBlock(); + } + + if (handlers.length === 0 && !finalizer) { + throwError({}, Messages.NoCatchOrFinally); + } + + return { + type: Syntax.TryStatement, + block: block, + guardedHandlers: [], + handlers: handlers, + finalizer: finalizer + }; + } + + // 12.15 The debugger statement + + function parseDebuggerStatement() { + expectKeyword('debugger'); + + consumeSemicolon(); + + return { + type: Syntax.DebuggerStatement + }; + } + + // 12 Statements + + function parseStatement() { + var token = lookahead(), + expr, + labeledBody; + + if (token.type === Token.EOF) { + throwUnexpected(token); + } + + if (token.type === Token.Punctuator) { + switch (token.value) { + case ';': + return parseEmptyStatement(); + case '{': + return parseBlock(); + case '(': + return parseExpressionStatement(); + default: + break; + } + } + + if (token.type === Token.Keyword) { + switch (token.value) { + case 'break': + return parseBreakStatement(); + case 'continue': + return parseContinueStatement(); + case 'debugger': + return parseDebuggerStatement(); + case 'do': + return parseDoWhileStatement(); + case 'for': + return parseForStatement(); + case 'function': + return parseFunctionDeclaration(); + case 'if': + return parseIfStatement(); + case 'return': + return parseReturnStatement(); + case 'switch': + return parseSwitchStatement(); + case 'throw': + return parseThrowStatement(); + case 'try': + return parseTryStatement(); + case 'var': + return parseVariableStatement(); + case 'while': + return parseWhileStatement(); + case 'with': + return parseWithStatement(); + default: + break; + } + } + + expr = parseExpression(); + + // 12.12 Labelled Statements + if ((expr.type === Syntax.Identifier) && match(':')) { + lex(); + + if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) { + throwError({}, Messages.Redeclaration, 'Label', expr.name); + } + + state.labelSet[expr.name] = true; + labeledBody = parseStatement(); + delete state.labelSet[expr.name]; + + return { + type: Syntax.LabeledStatement, + label: expr, + body: labeledBody + }; + } + + consumeSemicolon(); + + return { + type: Syntax.ExpressionStatement, + expression: expr + }; + } + + // 13 Function Definition + + function parseFunctionSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted, + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody; + + expect('{'); + + while (index < length) { + token = lookahead(); + if (token.type !== Token.StringLiteral) { + break; + } + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = sliceSource(token.range[0] + 1, token.range[1] - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + oldLabelSet = state.labelSet; + oldInIteration = state.inIteration; + oldInSwitch = state.inSwitch; + oldInFunctionBody = state.inFunctionBody; + + state.labelSet = {}; + state.inIteration = false; + state.inSwitch = false; + state.inFunctionBody = true; + + while (index < length) { + if (match('}')) { + break; + } + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + + expect('}'); + + state.labelSet = oldLabelSet; + state.inIteration = oldInIteration; + state.inSwitch = oldInSwitch; + state.inFunctionBody = oldInFunctionBody; + + return { + type: Syntax.BlockStatement, + body: sourceElements + }; + } + + function parseFunctionDeclaration() { + var id, param, params = [], body, token, stricted, firstRestricted, message, previousStrict, paramSet; + + expectKeyword('function'); + token = lookahead(); + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + + expect('('); + + if (!match(')')) { + paramSet = {}; + while (index < length) { + token = lookahead(); + param = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + stricted = token; + message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { + stricted = token; + message = Messages.StrictParamDupe; + } + } else if (!firstRestricted) { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { + firstRestricted = token; + message = Messages.StrictParamDupe; + } + } + params.push(param); + paramSet[param.name] = true; + if (match(')')) { + break; + } + expect(','); + } + } + + expect(')'); + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && stricted) { + throwErrorTolerant(stricted, message); + } + strict = previousStrict; + + return { + type: Syntax.FunctionDeclaration, + id: id, + params: params, + defaults: [], + body: body, + rest: null, + generator: false, + expression: false + }; + } + + function parseFunctionExpression() { + var token, id = null, stricted, firstRestricted, message, param, params = [], body, previousStrict, paramSet; + + expectKeyword('function'); + + if (!match('(')) { + token = lookahead(); + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + } + + expect('('); + + if (!match(')')) { + paramSet = {}; + while (index < length) { + token = lookahead(); + param = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + stricted = token; + message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { + stricted = token; + message = Messages.StrictParamDupe; + } + } else if (!firstRestricted) { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { + firstRestricted = token; + message = Messages.StrictParamDupe; + } + } + params.push(param); + paramSet[param.name] = true; + if (match(')')) { + break; + } + expect(','); + } + } + + expect(')'); + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && stricted) { + throwErrorTolerant(stricted, message); + } + strict = previousStrict; + + return { + type: Syntax.FunctionExpression, + id: id, + params: params, + defaults: [], + body: body, + rest: null, + generator: false, + expression: false + }; + } + + // 14 Program + + function parseSourceElement() { + var token = lookahead(); + + if (token.type === Token.Keyword) { + switch (token.value) { + case 'const': + case 'let': + return parseConstLetDeclaration(token.value); + case 'function': + return parseFunctionDeclaration(); + default: + return parseStatement(); + } + } + + if (token.type !== Token.EOF) { + return parseStatement(); + } + } + + function parseSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted; + + while (index < length) { + token = lookahead(); + if (token.type !== Token.StringLiteral) { + break; + } + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = sliceSource(token.range[0] + 1, token.range[1] - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + while (index < length) { + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + return sourceElements; + } + + function parseProgram() { + var program; + strict = false; + program = { + type: Syntax.Program, + body: parseSourceElements() + }; + return program; + } + + // The following functions are needed only when the option to preserve + // the comments is active. + + function addComment(type, value, start, end, loc) { + assert(typeof start === 'number', 'Comment must have valid position'); + + // Because the way the actual token is scanned, often the comments + // (if any) are skipped twice during the lexical analysis. + // Thus, we need to skip adding a comment if the comment array already + // handled it. + if (extra.comments.length > 0) { + if (extra.comments[extra.comments.length - 1].range[1] > start) { + return; + } + } + + extra.comments.push({ + type: type, + value: value, + range: [start, end], + loc: loc + }); + } + + function scanComment() { + var comment, ch, loc, start, blockComment, lineComment; + + comment = ''; + blockComment = false; + lineComment = false; + + while (index < length) { + ch = source[index]; + + if (lineComment) { + ch = source[index++]; + if (isLineTerminator(ch)) { + loc.end = { + line: lineNumber, + column: index - lineStart - 1 + }; + lineComment = false; + addComment('Line', comment, start, index - 1, loc); + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + comment = ''; + } else if (index >= length) { + lineComment = false; + comment += ch; + loc.end = { + line: lineNumber, + column: length - lineStart + }; + addComment('Line', comment, start, length, loc); + } else { + comment += ch; + } + } else if (blockComment) { + if (isLineTerminator(ch)) { + if (ch === '\r' && source[index + 1] === '\n') { + ++index; + comment += '\r\n'; + } else { + comment += ch; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + ch = source[index++]; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + comment += ch; + if (ch === '*') { + ch = source[index]; + if (ch === '/') { + comment = comment.substr(0, comment.length - 1); + blockComment = false; + ++index; + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Block', comment, start, index, loc); + comment = ''; + } + } + } + } else if (ch === '/') { + ch = source[index + 1]; + if (ch === '/') { + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + start = index; + index += 2; + lineComment = true; + if (index >= length) { + loc.end = { + line: lineNumber, + column: index - lineStart + }; + lineComment = false; + addComment('Line', comment, start, index, loc); + } + } else if (ch === '*') { + start = index; + index += 2; + blockComment = true; + loc = { + start: { + line: lineNumber, + column: index - lineStart - 2 + } + }; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + break; + } + } else if (isWhiteSpace(ch)) { + ++index; + } else if (isLineTerminator(ch)) { + ++index; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + } else { + break; + } + } + } + + function filterCommentLocation() { + var i, entry, comment, comments = []; + + for (i = 0; i < extra.comments.length; ++i) { + entry = extra.comments[i]; + comment = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + comment.range = entry.range; + } + if (extra.loc) { + comment.loc = entry.loc; + } + comments.push(comment); + } + + extra.comments = comments; + } + + function collectToken() { + var start, loc, token, range, value; + + skipComment(); + start = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + token = extra.advance(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + if (token.type !== Token.EOF) { + range = [token.range[0], token.range[1]]; + value = sliceSource(token.range[0], token.range[1]); + extra.tokens.push({ + type: TokenName[token.type], + value: value, + range: range, + loc: loc + }); + } + + return token; + } + + function collectRegex() { + var pos, loc, regex, token; + + skipComment(); + + pos = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + regex = extra.scanRegExp(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + // Pop the previous token, which is likely '/' or '/=' + if (extra.tokens.length > 0) { + token = extra.tokens[extra.tokens.length - 1]; + if (token.range[0] === pos && token.type === 'Punctuator') { + if (token.value === '/' || token.value === '/=') { + extra.tokens.pop(); + } + } + } + + extra.tokens.push({ + type: 'RegularExpression', + value: regex.literal, + range: [pos, index], + loc: loc + }); + + return regex; + } + + function filterTokenLocation() { + var i, entry, token, tokens = []; + + for (i = 0; i < extra.tokens.length; ++i) { + entry = extra.tokens[i]; + token = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + token.range = entry.range; + } + if (extra.loc) { + token.loc = entry.loc; + } + tokens.push(token); + } + + extra.tokens = tokens; + } + + function createLiteral(token) { + return { + type: Syntax.Literal, + value: token.value + }; + } + + function createRawLiteral(token) { + return { + type: Syntax.Literal, + value: token.value, + raw: sliceSource(token.range[0], token.range[1]) + }; + } + + function createLocationMarker() { + var marker = {}; + + marker.range = [index, index]; + marker.loc = { + start: { + line: lineNumber, + column: index - lineStart + }, + end: { + line: lineNumber, + column: index - lineStart + } + }; + + marker.end = function () { + this.range[1] = index; + this.loc.end.line = lineNumber; + this.loc.end.column = index - lineStart; + }; + + marker.applyGroup = function (node) { + if (extra.range) { + node.groupRange = [this.range[0], this.range[1]]; + } + if (extra.loc) { + node.groupLoc = { + start: { + line: this.loc.start.line, + column: this.loc.start.column + }, + end: { + line: this.loc.end.line, + column: this.loc.end.column + } + }; + } + }; + + marker.apply = function (node) { + if (extra.range) { + node.range = [this.range[0], this.range[1]]; + } + if (extra.loc) { + node.loc = { + start: { + line: this.loc.start.line, + column: this.loc.start.column + }, + end: { + line: this.loc.end.line, + column: this.loc.end.column + } + }; + } + }; + + return marker; + } + + function trackGroupExpression() { + var marker, expr; + + skipComment(); + marker = createLocationMarker(); + expect('('); + + expr = parseExpression(); + + expect(')'); + + marker.end(); + marker.applyGroup(expr); + + return expr; + } + + function trackLeftHandSideExpression() { + var marker, expr; + + skipComment(); + marker = createLocationMarker(); + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[')) { + if (match('[')) { + expr = { + type: Syntax.MemberExpression, + computed: true, + object: expr, + property: parseComputedMember() + }; + marker.end(); + marker.apply(expr); + } else { + expr = { + type: Syntax.MemberExpression, + computed: false, + object: expr, + property: parseNonComputedMember() + }; + marker.end(); + marker.apply(expr); + } + } + + return expr; + } + + function trackLeftHandSideExpressionAllowCall() { + var marker, expr; + + skipComment(); + marker = createLocationMarker(); + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || match('(')) { + if (match('(')) { + expr = { + type: Syntax.CallExpression, + callee: expr, + 'arguments': parseArguments() + }; + marker.end(); + marker.apply(expr); + } else if (match('[')) { + expr = { + type: Syntax.MemberExpression, + computed: true, + object: expr, + property: parseComputedMember() + }; + marker.end(); + marker.apply(expr); + } else { + expr = { + type: Syntax.MemberExpression, + computed: false, + object: expr, + property: parseNonComputedMember() + }; + marker.end(); + marker.apply(expr); + } + } + + return expr; + } + + function filterGroup(node) { + var n, i, entry; + + n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {}; + for (i in node) { + if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') { + entry = node[i]; + if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) { + n[i] = entry; + } else { + n[i] = filterGroup(entry); + } + } + } + return n; + } + + function wrapTrackingFunction(range, loc) { + + return function (parseFunction) { + + function isBinary(node) { + return node.type === Syntax.LogicalExpression || + node.type === Syntax.BinaryExpression; + } + + function visit(node) { + var start, end; + + if (isBinary(node.left)) { + visit(node.left); + } + if (isBinary(node.right)) { + visit(node.right); + } + + if (range) { + if (node.left.groupRange || node.right.groupRange) { + start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0]; + end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1]; + node.range = [start, end]; + } else if (typeof node.range === 'undefined') { + start = node.left.range[0]; + end = node.right.range[1]; + node.range = [start, end]; + } + } + if (loc) { + if (node.left.groupLoc || node.right.groupLoc) { + start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start; + end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end; + node.loc = { + start: start, + end: end + }; + } else if (typeof node.loc === 'undefined') { + node.loc = { + start: node.left.loc.start, + end: node.right.loc.end + }; + } + } + } + + return function () { + var marker, node; + + skipComment(); + + marker = createLocationMarker(); + node = parseFunction.apply(null, arguments); + marker.end(); + + if (range && typeof node.range === 'undefined') { + marker.apply(node); + } + + if (loc && typeof node.loc === 'undefined') { + marker.apply(node); + } + + if (isBinary(node)) { + visit(node); + } + + return node; + }; + }; + } + + function patch() { + + var wrapTracking; + + if (extra.comments) { + extra.skipComment = skipComment; + skipComment = scanComment; + } + + if (extra.raw) { + extra.createLiteral = createLiteral; + createLiteral = createRawLiteral; + } + + if (extra.range || extra.loc) { + + extra.parseGroupExpression = parseGroupExpression; + extra.parseLeftHandSideExpression = parseLeftHandSideExpression; + extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall; + parseGroupExpression = trackGroupExpression; + parseLeftHandSideExpression = trackLeftHandSideExpression; + parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall; + + wrapTracking = wrapTrackingFunction(extra.range, extra.loc); + + extra.parseAdditiveExpression = parseAdditiveExpression; + extra.parseAssignmentExpression = parseAssignmentExpression; + extra.parseBitwiseANDExpression = parseBitwiseANDExpression; + extra.parseBitwiseORExpression = parseBitwiseORExpression; + extra.parseBitwiseXORExpression = parseBitwiseXORExpression; + extra.parseBlock = parseBlock; + extra.parseFunctionSourceElements = parseFunctionSourceElements; + extra.parseCatchClause = parseCatchClause; + extra.parseComputedMember = parseComputedMember; + extra.parseConditionalExpression = parseConditionalExpression; + extra.parseConstLetDeclaration = parseConstLetDeclaration; + extra.parseEqualityExpression = parseEqualityExpression; + extra.parseExpression = parseExpression; + extra.parseForVariableDeclaration = parseForVariableDeclaration; + extra.parseFunctionDeclaration = parseFunctionDeclaration; + extra.parseFunctionExpression = parseFunctionExpression; + extra.parseLogicalANDExpression = parseLogicalANDExpression; + extra.parseLogicalORExpression = parseLogicalORExpression; + extra.parseMultiplicativeExpression = parseMultiplicativeExpression; + extra.parseNewExpression = parseNewExpression; + extra.parseNonComputedProperty = parseNonComputedProperty; + extra.parseObjectProperty = parseObjectProperty; + extra.parseObjectPropertyKey = parseObjectPropertyKey; + extra.parsePostfixExpression = parsePostfixExpression; + extra.parsePrimaryExpression = parsePrimaryExpression; + extra.parseProgram = parseProgram; + extra.parsePropertyFunction = parsePropertyFunction; + extra.parseRelationalExpression = parseRelationalExpression; + extra.parseStatement = parseStatement; + extra.parseShiftExpression = parseShiftExpression; + extra.parseSwitchCase = parseSwitchCase; + extra.parseUnaryExpression = parseUnaryExpression; + extra.parseVariableDeclaration = parseVariableDeclaration; + extra.parseVariableIdentifier = parseVariableIdentifier; + + parseAdditiveExpression = wrapTracking(extra.parseAdditiveExpression); + parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression); + parseBitwiseANDExpression = wrapTracking(extra.parseBitwiseANDExpression); + parseBitwiseORExpression = wrapTracking(extra.parseBitwiseORExpression); + parseBitwiseXORExpression = wrapTracking(extra.parseBitwiseXORExpression); + parseBlock = wrapTracking(extra.parseBlock); + parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements); + parseCatchClause = wrapTracking(extra.parseCatchClause); + parseComputedMember = wrapTracking(extra.parseComputedMember); + parseConditionalExpression = wrapTracking(extra.parseConditionalExpression); + parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration); + parseEqualityExpression = wrapTracking(extra.parseEqualityExpression); + parseExpression = wrapTracking(extra.parseExpression); + parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration); + parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration); + parseFunctionExpression = wrapTracking(extra.parseFunctionExpression); + parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression); + parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression); + parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression); + parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression); + parseNewExpression = wrapTracking(extra.parseNewExpression); + parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty); + parseObjectProperty = wrapTracking(extra.parseObjectProperty); + parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey); + parsePostfixExpression = wrapTracking(extra.parsePostfixExpression); + parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression); + parseProgram = wrapTracking(extra.parseProgram); + parsePropertyFunction = wrapTracking(extra.parsePropertyFunction); + parseRelationalExpression = wrapTracking(extra.parseRelationalExpression); + parseStatement = wrapTracking(extra.parseStatement); + parseShiftExpression = wrapTracking(extra.parseShiftExpression); + parseSwitchCase = wrapTracking(extra.parseSwitchCase); + parseUnaryExpression = wrapTracking(extra.parseUnaryExpression); + parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration); + parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier); + } + + if (typeof extra.tokens !== 'undefined') { + extra.advance = advance; + extra.scanRegExp = scanRegExp; + + advance = collectToken; + scanRegExp = collectRegex; + } + } + + function unpatch() { + if (typeof extra.skipComment === 'function') { + skipComment = extra.skipComment; + } + + if (extra.raw) { + createLiteral = extra.createLiteral; + } + + if (extra.range || extra.loc) { + parseAdditiveExpression = extra.parseAdditiveExpression; + parseAssignmentExpression = extra.parseAssignmentExpression; + parseBitwiseANDExpression = extra.parseBitwiseANDExpression; + parseBitwiseORExpression = extra.parseBitwiseORExpression; + parseBitwiseXORExpression = extra.parseBitwiseXORExpression; + parseBlock = extra.parseBlock; + parseFunctionSourceElements = extra.parseFunctionSourceElements; + parseCatchClause = extra.parseCatchClause; + parseComputedMember = extra.parseComputedMember; + parseConditionalExpression = extra.parseConditionalExpression; + parseConstLetDeclaration = extra.parseConstLetDeclaration; + parseEqualityExpression = extra.parseEqualityExpression; + parseExpression = extra.parseExpression; + parseForVariableDeclaration = extra.parseForVariableDeclaration; + parseFunctionDeclaration = extra.parseFunctionDeclaration; + parseFunctionExpression = extra.parseFunctionExpression; + parseGroupExpression = extra.parseGroupExpression; + parseLeftHandSideExpression = extra.parseLeftHandSideExpression; + parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall; + parseLogicalANDExpression = extra.parseLogicalANDExpression; + parseLogicalORExpression = extra.parseLogicalORExpression; + parseMultiplicativeExpression = extra.parseMultiplicativeExpression; + parseNewExpression = extra.parseNewExpression; + parseNonComputedProperty = extra.parseNonComputedProperty; + parseObjectProperty = extra.parseObjectProperty; + parseObjectPropertyKey = extra.parseObjectPropertyKey; + parsePrimaryExpression = extra.parsePrimaryExpression; + parsePostfixExpression = extra.parsePostfixExpression; + parseProgram = extra.parseProgram; + parsePropertyFunction = extra.parsePropertyFunction; + parseRelationalExpression = extra.parseRelationalExpression; + parseStatement = extra.parseStatement; + parseShiftExpression = extra.parseShiftExpression; + parseSwitchCase = extra.parseSwitchCase; + parseUnaryExpression = extra.parseUnaryExpression; + parseVariableDeclaration = extra.parseVariableDeclaration; + parseVariableIdentifier = extra.parseVariableIdentifier; + } + + if (typeof extra.scanRegExp === 'function') { + advance = extra.advance; + scanRegExp = extra.scanRegExp; + } + } + + function stringToArray(str) { + var length = str.length, + result = [], + i; + for (i = 0; i < length; ++i) { + result[i] = str.charAt(i); + } + return result; + } + + function parse(code, options) { + var program, toString; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + buffer = null; + state = { + allowIn: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false + }; + + extra = {}; + if (typeof options !== 'undefined') { + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + extra.raw = (typeof options.raw === 'boolean') && options.raw; + if (typeof options.tokens === 'boolean' && options.tokens) { + extra.tokens = []; + } + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + } + + if (length > 0) { + if (typeof source[0] === 'undefined') { + // Try first to convert to a string. This is good as fast path + // for old IE which understands string indexing for string + // literals only and not for string object. + if (code instanceof String) { + source = code.valueOf(); + } + + // Force accessing the characters via an array. + if (typeof source[0] === 'undefined') { + source = stringToArray(code); + } + } + } + + patch(); + try { + program = parseProgram(); + if (typeof extra.comments !== 'undefined') { + filterCommentLocation(); + program.comments = extra.comments; + } + if (typeof extra.tokens !== 'undefined') { + filterTokenLocation(); + program.tokens = extra.tokens; + } + if (typeof extra.errors !== 'undefined') { + program.errors = extra.errors; + } + if (extra.range || extra.loc) { + program.body = filterGroup(program.body); + } + } catch (e) { + throw e; + } finally { + unpatch(); + extra = {}; + } + + return program; + } + + // Sync with package.json. + exports.version = '1.0.4'; + + exports.parse = parse; + + // Deep copy. + exports.Syntax = (function () { + var name, types = {}; + + if (typeof Object.create === 'function') { + types = Object.create(null); + } + + for (name in Syntax) { + if (Syntax.hasOwnProperty(name)) { + types[name] = Syntax[name]; + } + } + + if (typeof Object.freeze === 'function') { + Object.freeze(types); + } + + return types; + }()); + +})); +/* vim: set sw=4 ts=4 et tw=80 : */ +/** + * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*global define, Reflect */ + +/* + * xpcshell has a smaller stack on linux and windows (1MB vs 9MB on mac), + * and the recursive nature of esprima can cause it to overflow pretty + * quickly. So favor it built in Reflect parser: + * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API + */ +define('esprimaAdapter', ['./esprima', 'env'], function (esprima, env) { + if (env.get() === 'xpconnect' && typeof Reflect !== 'undefined') { + return Reflect; + } else { + return esprima; + } +}); +define('uglifyjs/consolidator', ["require", "exports", "module", "./parse-js", "./process"], function(require, exports, module) { +/** + * @preserve Copyright 2012 Robert Gust-Bardon . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * @fileoverview Enhances UglifyJS with consolidation of null, Boolean, and String values. + *

    Also known as aliasing, this feature has been deprecated in the Closure Compiler since its + * initial release, where it is unavailable from the CLI. The Closure Compiler allows one to log and + * influence this process. In contrast, this implementation does not introduce + * any variable declarations in global code and derives String values from + * identifier names used as property accessors.

    + *

    Consolidating literals may worsen the data compression ratio when an encoding + * transformation is applied. For instance, jQuery 1.7.1 takes 248235 bytes. + * Building it with + * UglifyJS v1.2.5 results in 93647 bytes (37.73% of the original) which are + * then compressed to 33154 bytes (13.36% of the original) using gzip(1). Building it with the same + * version of UglifyJS 1.2.5 patched with the implementation of consolidation + * results in 80784 bytes (a decrease of 12863 bytes, i.e. 13.74%, in comparison + * to the aforementioned 93647 bytes) which are then compressed to 34013 bytes + * (an increase of 859 bytes, i.e. 2.59%, in comparison to the aforementioned + * 33154 bytes).

    + *

    Written in the strict variant + * of ECMA-262 5.1 Edition. Encoded in UTF-8. Follows Revision 2.28 of the Google JavaScript Style Guide (except for the + * discouraged use of the {@code function} tag and the {@code namespace} tag). + * 100% typed for the Closure Compiler Version 1741.

    + *

    Should you find this software useful, please consider a donation.

    + * @author follow.me@RGustBardon (Robert Gust-Bardon) + * @supported Tested with: + * + */ + +/*global console:false, exports:true, module:false, require:false */ +/*jshint sub:true */ +/** + * Consolidates null, Boolean, and String values found inside an AST. + * @param {!TSyntacticCodeUnit} oAbstractSyntaxTree An array-like object + * representing an AST. + * @return {!TSyntacticCodeUnit} An array-like object representing an AST with its null, Boolean, and + * String values consolidated. + */ +// TODO(user) Consolidation of mathematical values found in numeric literals. +// TODO(user) Unconsolidation. +// TODO(user) Consolidation of ECMA-262 6th Edition programs. +// TODO(user) Rewrite in ECMA-262 6th Edition. +exports['ast_consolidate'] = function(oAbstractSyntaxTree) { + 'use strict'; + /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:true, + latedef:true, newcap:true, noarge:true, noempty:true, nonew:true, + onevar:true, plusplus:true, regexp:true, undef:true, strict:true, + sub:false, trailing:true */ + + var _, + /** + * A record consisting of data about one or more source elements. + * @constructor + * @nosideeffects + */ + TSourceElementsData = function() { + /** + * The category of the elements. + * @type {number} + * @see ESourceElementCategories + */ + this.nCategory = ESourceElementCategories.N_OTHER; + /** + * The number of occurrences (within the elements) of each primitive + * value that could be consolidated. + * @type {!Array.>} + */ + this.aCount = []; + this.aCount[EPrimaryExpressionCategories.N_IDENTIFIER_NAMES] = {}; + this.aCount[EPrimaryExpressionCategories.N_STRING_LITERALS] = {}; + this.aCount[EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS] = + {}; + /** + * Identifier names found within the elements. + * @type {!Array.} + */ + this.aIdentifiers = []; + /** + * Prefixed representation Strings of each primitive value that could be + * consolidated within the elements. + * @type {!Array.} + */ + this.aPrimitiveValues = []; + }, + /** + * A record consisting of data about a primitive value that could be + * consolidated. + * @constructor + * @nosideeffects + */ + TPrimitiveValue = function() { + /** + * The difference in the number of terminal symbols between the original + * source text and the one with the primitive value consolidated. If the + * difference is positive, the primitive value is considered worthwhile. + * @type {number} + */ + this.nSaving = 0; + /** + * An identifier name of the variable that will be declared and assigned + * the primitive value if the primitive value is consolidated. + * @type {string} + */ + this.sName = ''; + }, + /** + * A record consisting of data on what to consolidate within the range of + * source elements that is currently being considered. + * @constructor + * @nosideeffects + */ + TSolution = function() { + /** + * An object whose keys are prefixed representation Strings of each + * primitive value that could be consolidated within the elements and + * whose values are corresponding data about those primitive values. + * @type {!Object.} + * @see TPrimitiveValue + */ + this.oPrimitiveValues = {}; + /** + * The difference in the number of terminal symbols between the original + * source text and the one with all the worthwhile primitive values + * consolidated. + * @type {number} + * @see TPrimitiveValue#nSaving + */ + this.nSavings = 0; + }, + /** + * The processor of ASTs found + * in UglifyJS. + * @namespace + * @type {!TProcessor} + */ + oProcessor = (/** @type {!TProcessor} */ require('./process')), + /** + * A record consisting of a number of constants that represent the + * difference in the number of terminal symbols between a source text with + * a modified syntactic code unit and the original one. + * @namespace + * @type {!Object.} + */ + oWeights = { + /** + * The difference in the number of punctuators required by the bracket + * notation and the dot notation. + *

    '[]'.length - '.'.length

    + * @const + * @type {number} + */ + N_PROPERTY_ACCESSOR: 1, + /** + * The number of punctuators required by a variable declaration with an + * initialiser. + *

    ':'.length + ';'.length

    + * @const + * @type {number} + */ + N_VARIABLE_DECLARATION: 2, + /** + * The number of terminal symbols required to introduce a variable + * statement (excluding its variable declaration list). + *

    'var '.length

    + * @const + * @type {number} + */ + N_VARIABLE_STATEMENT_AFFIXATION: 4, + /** + * The number of terminal symbols needed to enclose source elements + * within a function call with no argument values to a function with an + * empty parameter list. + *

    '(function(){}());'.length

    + * @const + * @type {number} + */ + N_CLOSURE: 17 + }, + /** + * Categories of primary expressions from which primitive values that + * could be consolidated are derivable. + * @namespace + * @enum {number} + */ + EPrimaryExpressionCategories = { + /** + * Identifier names used as property accessors. + * @type {number} + */ + N_IDENTIFIER_NAMES: 0, + /** + * String literals. + * @type {number} + */ + N_STRING_LITERALS: 1, + /** + * Null and Boolean literals. + * @type {number} + */ + N_NULL_AND_BOOLEAN_LITERALS: 2 + }, + /** + * Prefixes of primitive values that could be consolidated. + * The String values of the prefixes must have same number of characters. + * The prefixes must not be used in any properties defined in any version + * of ECMA-262. + * @namespace + * @enum {string} + */ + EValuePrefixes = { + /** + * Identifies String values. + * @type {string} + */ + S_STRING: '#S', + /** + * Identifies null and Boolean values. + * @type {string} + */ + S_SYMBOLIC: '#O' + }, + /** + * Categories of source elements in terms of their appropriateness of + * having their primitive values consolidated. + * @namespace + * @enum {number} + */ + ESourceElementCategories = { + /** + * Identifies a source element that includes the {@code with} statement. + * @type {number} + */ + N_WITH: 0, + /** + * Identifies a source element that includes the {@code eval} identifier name. + * @type {number} + */ + N_EVAL: 1, + /** + * Identifies a source element that must be excluded from the process + * unless its whole scope is examined. + * @type {number} + */ + N_EXCLUDABLE: 2, + /** + * Identifies source elements not posing any problems. + * @type {number} + */ + N_OTHER: 3 + }, + /** + * The list of literals (other than the String ones) whose primitive + * values can be consolidated. + * @const + * @type {!Array.} + */ + A_OTHER_SUBSTITUTABLE_LITERALS = [ + 'null', // The null literal. + 'false', // The Boolean literal {@code false}. + 'true' // The Boolean literal {@code true}. + ]; + + (/** + * Consolidates all worthwhile primitive values in a syntactic code unit. + * @param {!TSyntacticCodeUnit} oSyntacticCodeUnit An array-like object + * representing the branch of the abstract syntax tree representing the + * syntactic code unit along with its scope. + * @see TPrimitiveValue#nSaving + */ + function fExamineSyntacticCodeUnit(oSyntacticCodeUnit) { + var _, + /** + * Indicates whether the syntactic code unit represents global code. + * @type {boolean} + */ + bIsGlobal = 'toplevel' === oSyntacticCodeUnit[0], + /** + * Indicates whether the whole scope is being examined. + * @type {boolean} + */ + bIsWhollyExaminable = !bIsGlobal, + /** + * An array-like object representing source elements that constitute a + * syntactic code unit. + * @type {!TSyntacticCodeUnit} + */ + oSourceElements, + /** + * A record consisting of data about the source element that is + * currently being examined. + * @type {!TSourceElementsData} + */ + oSourceElementData, + /** + * The scope of the syntactic code unit. + * @type {!TScope} + */ + oScope, + /** + * An instance of an object that allows the traversal of an AST. + * @type {!TWalker} + */ + oWalker, + /** + * An object encompassing collections of functions used during the + * traversal of an AST. + * @namespace + * @type {!Object.>} + */ + oWalkers = { + /** + * A collection of functions used during the surveyance of source + * elements. + * @namespace + * @type {!Object.} + */ + oSurveySourceElement: { + /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys. + /** + * Classifies the source element as excludable if it does not + * contain a {@code with} statement or the {@code eval} identifier + * name. Adds the identifier of the function and its formal + * parameters to the list of identifier names found. + * @param {string} sIdentifier The identifier of the function. + * @param {!Array.} aFormalParameterList Formal parameters. + * @param {!TSyntacticCodeUnit} oFunctionBody Function code. + */ + 'defun': function( + sIdentifier, + aFormalParameterList, + oFunctionBody) { + fClassifyAsExcludable(); + fAddIdentifier(sIdentifier); + aFormalParameterList.forEach(fAddIdentifier); + }, + /** + * Increments the count of the number of occurrences of the String + * value that is equivalent to the sequence of terminal symbols + * that constitute the encountered identifier name. + * @param {!TSyntacticCodeUnit} oExpression The nonterminal + * MemberExpression. + * @param {string} sIdentifierName The identifier name used as the + * property accessor. + * @return {!Array} The encountered branch of an AST with its nonterminal + * MemberExpression traversed. + */ + 'dot': function(oExpression, sIdentifierName) { + fCountPrimaryExpression( + EPrimaryExpressionCategories.N_IDENTIFIER_NAMES, + EValuePrefixes.S_STRING + sIdentifierName); + return ['dot', oWalker.walk(oExpression), sIdentifierName]; + }, + /** + * Adds the optional identifier of the function and its formal + * parameters to the list of identifier names found. + * @param {?string} sIdentifier The optional identifier of the + * function. + * @param {!Array.} aFormalParameterList Formal parameters. + * @param {!TSyntacticCodeUnit} oFunctionBody Function code. + */ + 'function': function( + sIdentifier, + aFormalParameterList, + oFunctionBody) { + if ('string' === typeof sIdentifier) { + fAddIdentifier(sIdentifier); + } + aFormalParameterList.forEach(fAddIdentifier); + }, + /** + * Either increments the count of the number of occurrences of the + * encountered null or Boolean value or classifies a source element + * as containing the {@code eval} identifier name. + * @param {string} sIdentifier The identifier encountered. + */ + 'name': function(sIdentifier) { + if (-1 !== A_OTHER_SUBSTITUTABLE_LITERALS.indexOf(sIdentifier)) { + fCountPrimaryExpression( + EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS, + EValuePrefixes.S_SYMBOLIC + sIdentifier); + } else { + if ('eval' === sIdentifier) { + oSourceElementData.nCategory = + ESourceElementCategories.N_EVAL; + } + fAddIdentifier(sIdentifier); + } + }, + /** + * Classifies the source element as excludable if it does not + * contain a {@code with} statement or the {@code eval} identifier + * name. + * @param {TSyntacticCodeUnit} oExpression The expression whose + * value is to be returned. + */ + 'return': function(oExpression) { + fClassifyAsExcludable(); + }, + /** + * Increments the count of the number of occurrences of the + * encountered String value. + * @param {string} sStringValue The String value of the string + * literal encountered. + */ + 'string': function(sStringValue) { + if (sStringValue.length > 0) { + fCountPrimaryExpression( + EPrimaryExpressionCategories.N_STRING_LITERALS, + EValuePrefixes.S_STRING + sStringValue); + } + }, + /** + * Adds the identifier reserved for an exception to the list of + * identifier names found. + * @param {!TSyntacticCodeUnit} oTry A block of code in which an + * exception can occur. + * @param {Array} aCatch The identifier reserved for an exception + * and a block of code to handle the exception. + * @param {TSyntacticCodeUnit} oFinally An optional block of code + * to be evaluated regardless of whether an exception occurs. + */ + 'try': function(oTry, aCatch, oFinally) { + if (Array.isArray(aCatch)) { + fAddIdentifier(aCatch[0]); + } + }, + /** + * Classifies the source element as excludable if it does not + * contain a {@code with} statement or the {@code eval} identifier + * name. Adds the identifier of each declared variable to the list + * of identifier names found. + * @param {!Array.} aVariableDeclarationList Variable + * declarations. + */ + 'var': function(aVariableDeclarationList) { + fClassifyAsExcludable(); + aVariableDeclarationList.forEach(fAddVariable); + }, + /** + * Classifies a source element as containing the {@code with} + * statement. + * @param {!TSyntacticCodeUnit} oExpression An expression whose + * value is to be converted to a value of type Object and + * become the binding object of a new object environment + * record of a new lexical environment in which the statement + * is to be executed. + * @param {!TSyntacticCodeUnit} oStatement The statement to be + * executed in the augmented lexical environment. + * @return {!Array} An empty array to stop the traversal. + */ + 'with': function(oExpression, oStatement) { + oSourceElementData.nCategory = ESourceElementCategories.N_WITH; + return []; + } + /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys. + }, + /** + * A collection of functions used while looking for nested functions. + * @namespace + * @type {!Object.} + */ + oExamineFunctions: { + /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys. + /** + * Orders an examination of a nested function declaration. + * @this {!TSyntacticCodeUnit} An array-like object representing + * the branch of an AST representing the syntactic code unit along with + * its scope. + * @return {!Array} An empty array to stop the traversal. + */ + 'defun': function() { + fExamineSyntacticCodeUnit(this); + return []; + }, + /** + * Orders an examination of a nested function expression. + * @this {!TSyntacticCodeUnit} An array-like object representing + * the branch of an AST representing the syntactic code unit along with + * its scope. + * @return {!Array} An empty array to stop the traversal. + */ + 'function': function() { + fExamineSyntacticCodeUnit(this); + return []; + } + /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys. + } + }, + /** + * Records containing data about source elements. + * @type {Array.} + */ + aSourceElementsData = [], + /** + * The index (in the source text order) of the source element + * immediately following a Directive Prologue. + * @type {number} + */ + nAfterDirectivePrologue = 0, + /** + * The index (in the source text order) of the source element that is + * currently being considered. + * @type {number} + */ + nPosition, + /** + * The index (in the source text order) of the source element that is + * the last element of the range of source elements that is currently + * being considered. + * @type {(undefined|number)} + */ + nTo, + /** + * Initiates the traversal of a source element. + * @param {!TWalker} oWalker An instance of an object that allows the + * traversal of an abstract syntax tree. + * @param {!TSyntacticCodeUnit} oSourceElement A source element from + * which the traversal should commence. + * @return {function(): !TSyntacticCodeUnit} A function that is able to + * initiate the traversal from a given source element. + */ + cContext = function(oWalker, oSourceElement) { + /** + * @return {!TSyntacticCodeUnit} A function that is able to + * initiate the traversal from a given source element. + */ + var fLambda = function() { + return oWalker.walk(oSourceElement); + }; + + return fLambda; + }, + /** + * Classifies the source element as excludable if it does not + * contain a {@code with} statement or the {@code eval} identifier + * name. + */ + fClassifyAsExcludable = function() { + if (oSourceElementData.nCategory === + ESourceElementCategories.N_OTHER) { + oSourceElementData.nCategory = + ESourceElementCategories.N_EXCLUDABLE; + } + }, + /** + * Adds an identifier to the list of identifier names found. + * @param {string} sIdentifier The identifier to be added. + */ + fAddIdentifier = function(sIdentifier) { + if (-1 === oSourceElementData.aIdentifiers.indexOf(sIdentifier)) { + oSourceElementData.aIdentifiers.push(sIdentifier); + } + }, + /** + * Adds the identifier of a variable to the list of identifier names + * found. + * @param {!Array} aVariableDeclaration A variable declaration. + */ + fAddVariable = function(aVariableDeclaration) { + fAddIdentifier(/** @type {string} */ aVariableDeclaration[0]); + }, + /** + * Increments the count of the number of occurrences of the prefixed + * String representation attributed to the primary expression. + * @param {number} nCategory The category of the primary expression. + * @param {string} sName The prefixed String representation attributed + * to the primary expression. + */ + fCountPrimaryExpression = function(nCategory, sName) { + if (!oSourceElementData.aCount[nCategory].hasOwnProperty(sName)) { + oSourceElementData.aCount[nCategory][sName] = 0; + if (-1 === oSourceElementData.aPrimitiveValues.indexOf(sName)) { + oSourceElementData.aPrimitiveValues.push(sName); + } + } + oSourceElementData.aCount[nCategory][sName] += 1; + }, + /** + * Consolidates all worthwhile primitive values in a range of source + * elements. + * @param {number} nFrom The index (in the source text order) of the + * source element that is the first element of the range. + * @param {number} nTo The index (in the source text order) of the + * source element that is the last element of the range. + * @param {boolean} bEnclose Indicates whether the range should be + * enclosed within a function call with no argument values to a + * function with an empty parameter list if any primitive values + * are consolidated. + * @see TPrimitiveValue#nSaving + */ + fExamineSourceElements = function(nFrom, nTo, bEnclose) { + var _, + /** + * The index of the last mangled name. + * @type {number} + */ + nIndex = oScope.cname, + /** + * The index of the source element that is currently being + * considered. + * @type {number} + */ + nPosition, + /** + * A collection of functions used during the consolidation of + * primitive values and identifier names used as property + * accessors. + * @namespace + * @type {!Object.} + */ + oWalkersTransformers = { + /** + * If the String value that is equivalent to the sequence of + * terminal symbols that constitute the encountered identifier + * name is worthwhile, a syntactic conversion from the dot + * notation to the bracket notation ensues with that sequence + * being substituted by an identifier name to which the value + * is assigned. + * Applies to property accessors that use the dot notation. + * @param {!TSyntacticCodeUnit} oExpression The nonterminal + * MemberExpression. + * @param {string} sIdentifierName The identifier name used as + * the property accessor. + * @return {!Array} A syntactic code unit that is equivalent to + * the one encountered. + * @see TPrimitiveValue#nSaving + */ + 'dot': function(oExpression, sIdentifierName) { + /** + * The prefixed String value that is equivalent to the + * sequence of terminal symbols that constitute the + * encountered identifier name. + * @type {string} + */ + var sPrefixed = EValuePrefixes.S_STRING + sIdentifierName; + + return oSolutionBest.oPrimitiveValues.hasOwnProperty( + sPrefixed) && + oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ? + ['sub', + oWalker.walk(oExpression), + ['name', + oSolutionBest.oPrimitiveValues[sPrefixed].sName]] : + ['dot', oWalker.walk(oExpression), sIdentifierName]; + }, + /** + * If the encountered identifier is a null or Boolean literal + * and its value is worthwhile, the identifier is substituted + * by an identifier name to which that value is assigned. + * Applies to identifier names. + * @param {string} sIdentifier The identifier encountered. + * @return {!Array} A syntactic code unit that is equivalent to + * the one encountered. + * @see TPrimitiveValue#nSaving + */ + 'name': function(sIdentifier) { + /** + * The prefixed representation String of the identifier. + * @type {string} + */ + var sPrefixed = EValuePrefixes.S_SYMBOLIC + sIdentifier; + + return [ + 'name', + oSolutionBest.oPrimitiveValues.hasOwnProperty(sPrefixed) && + oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ? + oSolutionBest.oPrimitiveValues[sPrefixed].sName : + sIdentifier + ]; + }, + /** + * If the encountered String value is worthwhile, it is + * substituted by an identifier name to which that value is + * assigned. + * Applies to String values. + * @param {string} sStringValue The String value of the string + * literal encountered. + * @return {!Array} A syntactic code unit that is equivalent to + * the one encountered. + * @see TPrimitiveValue#nSaving + */ + 'string': function(sStringValue) { + /** + * The prefixed representation String of the primitive value + * of the literal. + * @type {string} + */ + var sPrefixed = + EValuePrefixes.S_STRING + sStringValue; + + return oSolutionBest.oPrimitiveValues.hasOwnProperty( + sPrefixed) && + oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ? + ['name', + oSolutionBest.oPrimitiveValues[sPrefixed].sName] : + ['string', sStringValue]; + } + }, + /** + * Such data on what to consolidate within the range of source + * elements that is currently being considered that lead to the + * greatest known reduction of the number of the terminal symbols + * in comparison to the original source text. + * @type {!TSolution} + */ + oSolutionBest = new TSolution(), + /** + * Data representing an ongoing attempt to find a better + * reduction of the number of the terminal symbols in comparison + * to the original source text than the best one that is + * currently known. + * @type {!TSolution} + * @see oSolutionBest + */ + oSolutionCandidate = new TSolution(), + /** + * A record consisting of data about the range of source elements + * that is currently being examined. + * @type {!TSourceElementsData} + */ + oSourceElementsData = new TSourceElementsData(), + /** + * Variable declarations for each primitive value that is to be + * consolidated within the elements. + * @type {!Array.} + */ + aVariableDeclarations = [], + /** + * Augments a list with a prefixed representation String. + * @param {!Array.} aList A list that is to be augmented. + * @return {function(string)} A function that augments a list + * with a prefixed representation String. + */ + cAugmentList = function(aList) { + /** + * @param {string} sPrefixed Prefixed representation String of + * a primitive value that could be consolidated within the + * elements. + */ + var fLambda = function(sPrefixed) { + if (-1 === aList.indexOf(sPrefixed)) { + aList.push(sPrefixed); + } + }; + + return fLambda; + }, + /** + * Adds the number of occurrences of a primitive value of a given + * category that could be consolidated in the source element with + * a given index to the count of occurrences of that primitive + * value within the range of source elements that is currently + * being considered. + * @param {number} nPosition The index (in the source text order) + * of a source element. + * @param {number} nCategory The category of the primary + * expression from which the primitive value is derived. + * @return {function(string)} A function that performs the + * addition. + * @see cAddOccurrencesInCategory + */ + cAddOccurrences = function(nPosition, nCategory) { + /** + * @param {string} sPrefixed The prefixed representation String + * of a primitive value. + */ + var fLambda = function(sPrefixed) { + if (!oSourceElementsData.aCount[nCategory].hasOwnProperty( + sPrefixed)) { + oSourceElementsData.aCount[nCategory][sPrefixed] = 0; + } + oSourceElementsData.aCount[nCategory][sPrefixed] += + aSourceElementsData[nPosition].aCount[nCategory][ + sPrefixed]; + }; + + return fLambda; + }, + /** + * Adds the number of occurrences of each primitive value of a + * given category that could be consolidated in the source + * element with a given index to the count of occurrences of that + * primitive values within the range of source elements that is + * currently being considered. + * @param {number} nPosition The index (in the source text order) + * of a source element. + * @return {function(number)} A function that performs the + * addition. + * @see fAddOccurrences + */ + cAddOccurrencesInCategory = function(nPosition) { + /** + * @param {number} nCategory The category of the primary + * expression from which the primitive value is derived. + */ + var fLambda = function(nCategory) { + Object.keys( + aSourceElementsData[nPosition].aCount[nCategory] + ).forEach(cAddOccurrences(nPosition, nCategory)); + }; + + return fLambda; + }, + /** + * Adds the number of occurrences of each primitive value that + * could be consolidated in the source element with a given index + * to the count of occurrences of that primitive values within + * the range of source elements that is currently being + * considered. + * @param {number} nPosition The index (in the source text order) + * of a source element. + */ + fAddOccurrences = function(nPosition) { + Object.keys(aSourceElementsData[nPosition].aCount).forEach( + cAddOccurrencesInCategory(nPosition)); + }, + /** + * Creates a variable declaration for a primitive value if that + * primitive value is to be consolidated within the elements. + * @param {string} sPrefixed Prefixed representation String of a + * primitive value that could be consolidated within the + * elements. + * @see aVariableDeclarations + */ + cAugmentVariableDeclarations = function(sPrefixed) { + if (oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0) { + aVariableDeclarations.push([ + oSolutionBest.oPrimitiveValues[sPrefixed].sName, + [0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC) ? + 'name' : 'string', + sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length)] + ]); + } + }, + /** + * Sorts primitive values with regard to the difference in the + * number of terminal symbols between the original source text + * and the one with those primitive values consolidated. + * @param {string} sPrefixed0 The prefixed representation String + * of the first of the two primitive values that are being + * compared. + * @param {string} sPrefixed1 The prefixed representation String + * of the second of the two primitive values that are being + * compared. + * @return {number} + *
    + *
    -1
    + *
    if the first primitive value must be placed before + * the other one,
    + *
    0
    + *
    if the first primitive value may be placed before + * the other one,
    + *
    1
    + *
    if the first primitive value must not be placed + * before the other one.
    + *
    + * @see TSolution.oPrimitiveValues + */ + cSortPrimitiveValues = function(sPrefixed0, sPrefixed1) { + /** + * The difference between: + *
      + *
    1. the difference in the number of terminal symbols + * between the original source text and the one with the + * first primitive value consolidated, and
    2. + *
    3. the difference in the number of terminal symbols + * between the original source text and the one with the + * second primitive value consolidated.
    4. + *
    + * @type {number} + */ + var nDifference = + oSolutionCandidate.oPrimitiveValues[sPrefixed0].nSaving - + oSolutionCandidate.oPrimitiveValues[sPrefixed1].nSaving; + + return nDifference > 0 ? -1 : nDifference < 0 ? 1 : 0; + }, + /** + * Assigns an identifier name to a primitive value and calculates + * whether instances of that primitive value are worth + * consolidating. + * @param {string} sPrefixed The prefixed representation String + * of a primitive value that is being evaluated. + */ + fEvaluatePrimitiveValue = function(sPrefixed) { + var _, + /** + * The index of the last mangled name. + * @type {number} + */ + nIndex, + /** + * The representation String of the primitive value that is + * being evaluated. + * @type {string} + */ + sName = + sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length), + /** + * The number of source characters taken up by the + * representation String of the primitive value that is + * being evaluated. + * @type {number} + */ + nLengthOriginal = sName.length, + /** + * The number of source characters taken up by the + * identifier name that could substitute the primitive + * value that is being evaluated. + * substituted. + * @type {number} + */ + nLengthSubstitution, + /** + * The number of source characters taken up by by the + * representation String of the primitive value that is + * being evaluated when it is represented by a string + * literal. + * @type {number} + */ + nLengthString = oProcessor.make_string(sName).length; + + oSolutionCandidate.oPrimitiveValues[sPrefixed] = + new TPrimitiveValue(); + do { // Find an identifier unused in this or any nested scope. + nIndex = oScope.cname; + oSolutionCandidate.oPrimitiveValues[sPrefixed].sName = + oScope.next_mangled(); + } while (-1 !== oSourceElementsData.aIdentifiers.indexOf( + oSolutionCandidate.oPrimitiveValues[sPrefixed].sName)); + nLengthSubstitution = oSolutionCandidate.oPrimitiveValues[ + sPrefixed].sName.length; + if (0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC)) { + // foo:null, or foo:null; + oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -= + nLengthSubstitution + nLengthOriginal + + oWeights.N_VARIABLE_DECLARATION; + // null vs foo + oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving += + oSourceElementsData.aCount[ + EPrimaryExpressionCategories. + N_NULL_AND_BOOLEAN_LITERALS][sPrefixed] * + (nLengthOriginal - nLengthSubstitution); + } else { + // foo:'fromCharCode'; + oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -= + nLengthSubstitution + nLengthString + + oWeights.N_VARIABLE_DECLARATION; + // .fromCharCode vs [foo] + if (oSourceElementsData.aCount[ + EPrimaryExpressionCategories.N_IDENTIFIER_NAMES + ].hasOwnProperty(sPrefixed)) { + oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving += + oSourceElementsData.aCount[ + EPrimaryExpressionCategories.N_IDENTIFIER_NAMES + ][sPrefixed] * + (nLengthOriginal - nLengthSubstitution - + oWeights.N_PROPERTY_ACCESSOR); + } + // 'fromCharCode' vs foo + if (oSourceElementsData.aCount[ + EPrimaryExpressionCategories.N_STRING_LITERALS + ].hasOwnProperty(sPrefixed)) { + oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving += + oSourceElementsData.aCount[ + EPrimaryExpressionCategories.N_STRING_LITERALS + ][sPrefixed] * + (nLengthString - nLengthSubstitution); + } + } + if (oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving > + 0) { + oSolutionCandidate.nSavings += + oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving; + } else { + oScope.cname = nIndex; // Free the identifier name. + } + }, + /** + * Adds a variable declaration to an existing variable statement. + * @param {!Array} aVariableDeclaration A variable declaration + * with an initialiser. + */ + cAddVariableDeclaration = function(aVariableDeclaration) { + (/** @type {!Array} */ oSourceElements[nFrom][1]).unshift( + aVariableDeclaration); + }; + + if (nFrom > nTo) { + return; + } + // If the range is a closure, reuse the closure. + if (nFrom === nTo && + 'stat' === oSourceElements[nFrom][0] && + 'call' === oSourceElements[nFrom][1][0] && + 'function' === oSourceElements[nFrom][1][1][0]) { + fExamineSyntacticCodeUnit(oSourceElements[nFrom][1][1]); + return; + } + // Create a list of all derived primitive values within the range. + for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) { + aSourceElementsData[nPosition].aPrimitiveValues.forEach( + cAugmentList(oSourceElementsData.aPrimitiveValues)); + } + if (0 === oSourceElementsData.aPrimitiveValues.length) { + return; + } + for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) { + // Add the number of occurrences to the total count. + fAddOccurrences(nPosition); + // Add identifiers of this or any nested scope to the list. + aSourceElementsData[nPosition].aIdentifiers.forEach( + cAugmentList(oSourceElementsData.aIdentifiers)); + } + // Distribute identifier names among derived primitive values. + do { // If there was any progress, find a better distribution. + oSolutionBest = oSolutionCandidate; + if (Object.keys(oSolutionCandidate.oPrimitiveValues).length > 0) { + // Sort primitive values descending by their worthwhileness. + oSourceElementsData.aPrimitiveValues.sort(cSortPrimitiveValues); + } + oSolutionCandidate = new TSolution(); + oSourceElementsData.aPrimitiveValues.forEach( + fEvaluatePrimitiveValue); + oScope.cname = nIndex; + } while (oSolutionCandidate.nSavings > oSolutionBest.nSavings); + // Take the necessity of adding a variable statement into account. + if ('var' !== oSourceElements[nFrom][0]) { + oSolutionBest.nSavings -= oWeights.N_VARIABLE_STATEMENT_AFFIXATION; + } + if (bEnclose) { + // Take the necessity of forming a closure into account. + oSolutionBest.nSavings -= oWeights.N_CLOSURE; + } + if (oSolutionBest.nSavings > 0) { + // Create variable declarations suitable for UglifyJS. + Object.keys(oSolutionBest.oPrimitiveValues).forEach( + cAugmentVariableDeclarations); + // Rewrite expressions that contain worthwhile primitive values. + for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) { + oWalker = oProcessor.ast_walker(); + oSourceElements[nPosition] = + oWalker.with_walkers( + oWalkersTransformers, + cContext(oWalker, oSourceElements[nPosition])); + } + if ('var' === oSourceElements[nFrom][0]) { // Reuse the statement. + (/** @type {!Array.} */ aVariableDeclarations.reverse( + )).forEach(cAddVariableDeclaration); + } else { // Add a variable statement. + Array.prototype.splice.call( + oSourceElements, + nFrom, + 0, + ['var', aVariableDeclarations]); + nTo += 1; + } + if (bEnclose) { + // Add a closure. + Array.prototype.splice.call( + oSourceElements, + nFrom, + 0, + ['stat', ['call', ['function', null, [], []], []]]); + // Copy source elements into the closure. + for (nPosition = nTo + 1; nPosition > nFrom; nPosition -= 1) { + Array.prototype.unshift.call( + oSourceElements[nFrom][1][1][3], + oSourceElements[nPosition]); + } + // Remove source elements outside the closure. + Array.prototype.splice.call( + oSourceElements, + nFrom + 1, + nTo - nFrom + 1); + } + } + if (bEnclose) { + // Restore the availability of identifier names. + oScope.cname = nIndex; + } + }; + + oSourceElements = (/** @type {!TSyntacticCodeUnit} */ + oSyntacticCodeUnit[bIsGlobal ? 1 : 3]); + if (0 === oSourceElements.length) { + return; + } + oScope = bIsGlobal ? oSyntacticCodeUnit.scope : oSourceElements.scope; + // Skip a Directive Prologue. + while (nAfterDirectivePrologue < oSourceElements.length && + 'directive' === oSourceElements[nAfterDirectivePrologue][0]) { + nAfterDirectivePrologue += 1; + aSourceElementsData.push(null); + } + if (oSourceElements.length === nAfterDirectivePrologue) { + return; + } + for (nPosition = nAfterDirectivePrologue; + nPosition < oSourceElements.length; + nPosition += 1) { + oSourceElementData = new TSourceElementsData(); + oWalker = oProcessor.ast_walker(); + // Classify a source element. + // Find its derived primitive values and count their occurrences. + // Find all identifiers used (including nested scopes). + oWalker.with_walkers( + oWalkers.oSurveySourceElement, + cContext(oWalker, oSourceElements[nPosition])); + // Establish whether the scope is still wholly examinable. + bIsWhollyExaminable = bIsWhollyExaminable && + ESourceElementCategories.N_WITH !== oSourceElementData.nCategory && + ESourceElementCategories.N_EVAL !== oSourceElementData.nCategory; + aSourceElementsData.push(oSourceElementData); + } + if (bIsWhollyExaminable) { // Examine the whole scope. + fExamineSourceElements( + nAfterDirectivePrologue, + oSourceElements.length - 1, + false); + } else { // Examine unexcluded ranges of source elements. + for (nPosition = oSourceElements.length - 1; + nPosition >= nAfterDirectivePrologue; + nPosition -= 1) { + oSourceElementData = (/** @type {!TSourceElementsData} */ + aSourceElementsData[nPosition]); + if (ESourceElementCategories.N_OTHER === + oSourceElementData.nCategory) { + if ('undefined' === typeof nTo) { + nTo = nPosition; // Indicate the end of a range. + } + // Examine the range if it immediately follows a Directive Prologue. + if (nPosition === nAfterDirectivePrologue) { + fExamineSourceElements(nPosition, nTo, true); + } + } else { + if ('undefined' !== typeof nTo) { + // Examine the range that immediately follows this source element. + fExamineSourceElements(nPosition + 1, nTo, true); + nTo = void 0; // Obliterate the range. + } + // Examine nested functions. + oWalker = oProcessor.ast_walker(); + oWalker.with_walkers( + oWalkers.oExamineFunctions, + cContext(oWalker, oSourceElements[nPosition])); + } + } + } + }(oAbstractSyntaxTree = oProcessor.ast_add_scope(oAbstractSyntaxTree))); + return oAbstractSyntaxTree; +}; +/*jshint sub:false */ + +/* Local Variables: */ +/* mode: js */ +/* coding: utf-8 */ +/* indent-tabs-mode: nil */ +/* tab-width: 2 */ +/* End: */ +/* vim: set ft=javascript fenc=utf-8 et ts=2 sts=2 sw=2: */ +/* :mode=javascript:noTabs=true:tabSize=2:indentSize=2:deepIndent=true: */ +}); +define('uglifyjs/parse-js', ["exports"], function(exports) { +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + + This version is suitable for Node.js. With minimal changes (the + exports stuff) it should work on any JS platform. + + This file contains the tokenizer/parser. It is a port to JavaScript + of parse-js [1], a JavaScript parser library written in Common Lisp + by Marijn Haverbeke. Thank you Marijn! + + [1] http://marijn.haverbeke.nl/parse-js/ + + Exported functions: + + - tokenizer(code) -- returns a function. Call the returned + function to fetch the next token. + + - parse(code) -- returns an AST of the given JavaScript code. + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2010 (c) Mihai Bazon + Based on parse-js (http://marijn.haverbeke.nl/parse-js/). + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +/* -----[ Tokenizer (constants) ]----- */ + +var KEYWORDS = array_to_hash([ + "break", + "case", + "catch", + "const", + "continue", + "debugger", + "default", + "delete", + "do", + "else", + "finally", + "for", + "function", + "if", + "in", + "instanceof", + "new", + "return", + "switch", + "throw", + "try", + "typeof", + "var", + "void", + "while", + "with" +]); + +var RESERVED_WORDS = array_to_hash([ + "abstract", + "boolean", + "byte", + "char", + "class", + "double", + "enum", + "export", + "extends", + "final", + "float", + "goto", + "implements", + "import", + "int", + "interface", + "long", + "native", + "package", + "private", + "protected", + "public", + "short", + "static", + "super", + "synchronized", + "throws", + "transient", + "volatile" +]); + +var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([ + "return", + "new", + "delete", + "throw", + "else", + "case" +]); + +var KEYWORDS_ATOM = array_to_hash([ + "false", + "null", + "true", + "undefined" +]); + +var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^")); + +var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; +var RE_OCT_NUMBER = /^0[0-7]+$/; +var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; + +var OPERATORS = array_to_hash([ + "in", + "instanceof", + "typeof", + "new", + "void", + "delete", + "++", + "--", + "+", + "-", + "!", + "~", + "&", + "|", + "^", + "*", + "/", + "%", + ">>", + "<<", + ">>>", + "<", + ">", + "<=", + ">=", + "==", + "===", + "!=", + "!==", + "?", + "=", + "+=", + "-=", + "/=", + "*=", + "%=", + ">>=", + "<<=", + ">>>=", + "|=", + "^=", + "&=", + "&&", + "||" +]); + +var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF")); + +var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{(,.;:")); + +var PUNC_CHARS = array_to_hash(characters("[]{}(),;:")); + +var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy")); + +/* -----[ Tokenizer ]----- */ + +var UNICODE = { // Unicode 6.1 + letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0\\u08A2-\\u08AC\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F0\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"), + combining_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u08E4-\\u08FE\\u0900-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2\\u09E3\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2\\u0AE3\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B56\\u0B57\\u0B62\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C01-\\u0C03\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0C82\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CE2\\u0CE3\\u0D02\\u0D03\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62\\u0D63\\u0D82\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E\\u0F3F\\u0F71-\\u0F84\\u0F86\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF2-\\u1CF4\\u1DC0-\\u1DE6\\u1DFC-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA674-\\uA67D\\uA69F\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA880\\uA881\\uA8B4-\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uAA29-\\uAA36\\uAA43\\uAA4C\\uAA4D\\uAA7B\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5\\uAAF6\\uABE3-\\uABEA\\uABEC\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"), + connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]"), + digit: new RegExp("[\\u0030-\\u0039\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]") +}; + +function is_letter(ch) { + return UNICODE.letter.test(ch); +}; + +function is_digit(ch) { + ch = ch.charCodeAt(0); + return ch >= 48 && ch <= 57; +}; + +function is_unicode_digit(ch) { + return UNICODE.digit.test(ch); +} + +function is_alphanumeric_char(ch) { + return is_digit(ch) || is_letter(ch); +}; + +function is_unicode_combining_mark(ch) { + return UNICODE.combining_mark.test(ch); +}; + +function is_unicode_connector_punctuation(ch) { + return UNICODE.connector_punctuation.test(ch); +}; + +function is_identifier_start(ch) { + return ch == "$" || ch == "_" || is_letter(ch); +}; + +function is_identifier_char(ch) { + return is_identifier_start(ch) + || is_unicode_combining_mark(ch) + || is_unicode_digit(ch) + || is_unicode_connector_punctuation(ch) + || ch == "\u200c" // zero-width non-joiner + || ch == "\u200d" // zero-width joiner (in my ECMA-262 PDF, this is also 200c) + ; +}; + +function parse_js_number(num) { + if (RE_HEX_NUMBER.test(num)) { + return parseInt(num.substr(2), 16); + } else if (RE_OCT_NUMBER.test(num)) { + return parseInt(num.substr(1), 8); + } else if (RE_DEC_NUMBER.test(num)) { + return parseFloat(num); + } +}; + +function JS_Parse_Error(message, line, col, pos) { + this.message = message; + this.line = line + 1; + this.col = col + 1; + this.pos = pos + 1; + this.stack = new Error().stack; +}; + +JS_Parse_Error.prototype.toString = function() { + return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack; +}; + +function js_error(message, line, col, pos) { + throw new JS_Parse_Error(message, line, col, pos); +}; + +function is_token(token, type, val) { + return token.type == type && (val == null || token.value == val); +}; + +var EX_EOF = {}; + +function tokenizer($TEXT) { + + var S = { + text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), + pos : 0, + tokpos : 0, + line : 0, + tokline : 0, + col : 0, + tokcol : 0, + newline_before : false, + regex_allowed : false, + comments_before : [] + }; + + function peek() { return S.text.charAt(S.pos); }; + + function next(signal_eof, in_string) { + var ch = S.text.charAt(S.pos++); + if (signal_eof && !ch) + throw EX_EOF; + if (ch == "\n") { + S.newline_before = S.newline_before || !in_string; + ++S.line; + S.col = 0; + } else { + ++S.col; + } + return ch; + }; + + function eof() { + return !S.peek(); + }; + + function find(what, signal_eof) { + var pos = S.text.indexOf(what, S.pos); + if (signal_eof && pos == -1) throw EX_EOF; + return pos; + }; + + function start_token() { + S.tokline = S.line; + S.tokcol = S.col; + S.tokpos = S.pos; + }; + + function token(type, value, is_comment) { + S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || + (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || + (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); + var ret = { + type : type, + value : value, + line : S.tokline, + col : S.tokcol, + pos : S.tokpos, + endpos : S.pos, + nlb : S.newline_before + }; + if (!is_comment) { + ret.comments_before = S.comments_before; + S.comments_before = []; + // make note of any newlines in the comments that came before + for (var i = 0, len = ret.comments_before.length; i < len; i++) { + ret.nlb = ret.nlb || ret.comments_before[i].nlb; + } + } + S.newline_before = false; + return ret; + }; + + function skip_whitespace() { + while (HOP(WHITESPACE_CHARS, peek())) + next(); + }; + + function read_while(pred) { + var ret = "", ch = peek(), i = 0; + while (ch && pred(ch, i++)) { + ret += next(); + ch = peek(); + } + return ret; + }; + + function parse_error(err) { + js_error(err, S.tokline, S.tokcol, S.tokpos); + }; + + function read_num(prefix) { + var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; + var num = read_while(function(ch, i){ + if (ch == "x" || ch == "X") { + if (has_x) return false; + return has_x = true; + } + if (!has_x && (ch == "E" || ch == "e")) { + if (has_e) return false; + return has_e = after_e = true; + } + if (ch == "-") { + if (after_e || (i == 0 && !prefix)) return true; + return false; + } + if (ch == "+") return after_e; + after_e = false; + if (ch == ".") { + if (!has_dot && !has_x && !has_e) + return has_dot = true; + return false; + } + return is_alphanumeric_char(ch); + }); + if (prefix) + num = prefix + num; + var valid = parse_js_number(num); + if (!isNaN(valid)) { + return token("num", valid); + } else { + parse_error("Invalid syntax: " + num); + } + }; + + function read_escaped_char(in_string) { + var ch = next(true, in_string); + switch (ch) { + case "n" : return "\n"; + case "r" : return "\r"; + case "t" : return "\t"; + case "b" : return "\b"; + case "v" : return "\u000b"; + case "f" : return "\f"; + case "0" : return "\0"; + case "x" : return String.fromCharCode(hex_bytes(2)); + case "u" : return String.fromCharCode(hex_bytes(4)); + case "\n": return ""; + default : return ch; + } + }; + + function hex_bytes(n) { + var num = 0; + for (; n > 0; --n) { + var digit = parseInt(next(true), 16); + if (isNaN(digit)) + parse_error("Invalid hex-character pattern in string"); + num = (num << 4) | digit; + } + return num; + }; + + function read_string() { + return with_eof_error("Unterminated string constant", function(){ + var quote = next(), ret = ""; + for (;;) { + var ch = next(true); + if (ch == "\\") { + // read OctalEscapeSequence (XXX: deprecated if "strict mode") + // https://github.com/mishoo/UglifyJS/issues/178 + var octal_len = 0, first = null; + ch = read_while(function(ch){ + if (ch >= "0" && ch <= "7") { + if (!first) { + first = ch; + return ++octal_len; + } + else if (first <= "3" && octal_len <= 2) return ++octal_len; + else if (first >= "4" && octal_len <= 1) return ++octal_len; + } + return false; + }); + if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8)); + else ch = read_escaped_char(true); + } + else if (ch == quote) break; + else if (ch == "\n") throw EX_EOF; + ret += ch; + } + return token("string", ret); + }); + }; + + function read_line_comment() { + next(); + var i = find("\n"), ret; + if (i == -1) { + ret = S.text.substr(S.pos); + S.pos = S.text.length; + } else { + ret = S.text.substring(S.pos, i); + S.pos = i; + } + return token("comment1", ret, true); + }; + + function read_multiline_comment() { + next(); + return with_eof_error("Unterminated multiline comment", function(){ + var i = find("*/", true), + text = S.text.substring(S.pos, i); + S.pos = i + 2; + S.line += text.split("\n").length - 1; + S.newline_before = S.newline_before || text.indexOf("\n") >= 0; + + // https://github.com/mishoo/UglifyJS/issues/#issue/100 + if (/^@cc_on/i.test(text)) { + warn("WARNING: at line " + S.line); + warn("*** Found \"conditional comment\": " + text); + warn("*** UglifyJS DISCARDS ALL COMMENTS. This means your code might no longer work properly in Internet Explorer."); + } + + return token("comment2", text, true); + }); + }; + + function read_name() { + var backslash = false, name = "", ch, escaped = false, hex; + while ((ch = peek()) != null) { + if (!backslash) { + if (ch == "\\") escaped = backslash = true, next(); + else if (is_identifier_char(ch)) name += next(); + else break; + } + else { + if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); + ch = read_escaped_char(); + if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); + name += ch; + backslash = false; + } + } + if (HOP(KEYWORDS, name) && escaped) { + hex = name.charCodeAt(0).toString(16).toUpperCase(); + name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1); + } + return name; + }; + + function read_regexp(regexp) { + return with_eof_error("Unterminated regular expression", function(){ + var prev_backslash = false, ch, in_class = false; + while ((ch = next(true))) if (prev_backslash) { + regexp += "\\" + ch; + prev_backslash = false; + } else if (ch == "[") { + in_class = true; + regexp += ch; + } else if (ch == "]" && in_class) { + in_class = false; + regexp += ch; + } else if (ch == "/" && !in_class) { + break; + } else if (ch == "\\") { + prev_backslash = true; + } else { + regexp += ch; + } + var mods = read_name(); + return token("regexp", [ regexp, mods ]); + }); + }; + + function read_operator(prefix) { + function grow(op) { + if (!peek()) return op; + var bigger = op + peek(); + if (HOP(OPERATORS, bigger)) { + next(); + return grow(bigger); + } else { + return op; + } + }; + return token("operator", grow(prefix || next())); + }; + + function handle_slash() { + next(); + var regex_allowed = S.regex_allowed; + switch (peek()) { + case "/": + S.comments_before.push(read_line_comment()); + S.regex_allowed = regex_allowed; + return next_token(); + case "*": + S.comments_before.push(read_multiline_comment()); + S.regex_allowed = regex_allowed; + return next_token(); + } + return S.regex_allowed ? read_regexp("") : read_operator("/"); + }; + + function handle_dot() { + next(); + return is_digit(peek()) + ? read_num(".") + : token("punc", "."); + }; + + function read_word() { + var word = read_name(); + return !HOP(KEYWORDS, word) + ? token("name", word) + : HOP(OPERATORS, word) + ? token("operator", word) + : HOP(KEYWORDS_ATOM, word) + ? token("atom", word) + : token("keyword", word); + }; + + function with_eof_error(eof_error, cont) { + try { + return cont(); + } catch(ex) { + if (ex === EX_EOF) parse_error(eof_error); + else throw ex; + } + }; + + function next_token(force_regexp) { + if (force_regexp != null) + return read_regexp(force_regexp); + skip_whitespace(); + start_token(); + var ch = peek(); + if (!ch) return token("eof"); + if (is_digit(ch)) return read_num(); + if (ch == '"' || ch == "'") return read_string(); + if (HOP(PUNC_CHARS, ch)) return token("punc", next()); + if (ch == ".") return handle_dot(); + if (ch == "/") return handle_slash(); + if (HOP(OPERATOR_CHARS, ch)) return read_operator(); + if (ch == "\\" || is_identifier_start(ch)) return read_word(); + parse_error("Unexpected character '" + ch + "'"); + }; + + next_token.context = function(nc) { + if (nc) S = nc; + return S; + }; + + return next_token; + +}; + +/* -----[ Parser (constants) ]----- */ + +var UNARY_PREFIX = array_to_hash([ + "typeof", + "void", + "delete", + "--", + "++", + "!", + "~", + "-", + "+" +]); + +var UNARY_POSTFIX = array_to_hash([ "--", "++" ]); + +var ASSIGNMENT = (function(a, ret, i){ + while (i < a.length) { + ret[a[i]] = a[i].substr(0, a[i].length - 1); + i++; + } + return ret; +})( + ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="], + { "=": true }, + 0 +); + +var PRECEDENCE = (function(a, ret){ + for (var i = 0, n = 1; i < a.length; ++i, ++n) { + var b = a[i]; + for (var j = 0; j < b.length; ++j) { + ret[b[j]] = n; + } + } + return ret; +})( + [ + ["||"], + ["&&"], + ["|"], + ["^"], + ["&"], + ["==", "===", "!=", "!=="], + ["<", ">", "<=", ">=", "in", "instanceof"], + [">>", "<<", ">>>"], + ["+", "-"], + ["*", "/", "%"] + ], + {} +); + +var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); + +var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); + +/* -----[ Parser ]----- */ + +function NodeWithToken(str, start, end) { + this.name = str; + this.start = start; + this.end = end; +}; + +NodeWithToken.prototype.toString = function() { return this.name; }; + +function parse($TEXT, exigent_mode, embed_tokens) { + + var S = { + input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT, + token : null, + prev : null, + peeked : null, + in_function : 0, + in_directives : true, + in_loop : 0, + labels : [] + }; + + S.token = next(); + + function is(type, value) { + return is_token(S.token, type, value); + }; + + function peek() { return S.peeked || (S.peeked = S.input()); }; + + function next() { + S.prev = S.token; + if (S.peeked) { + S.token = S.peeked; + S.peeked = null; + } else { + S.token = S.input(); + } + S.in_directives = S.in_directives && ( + S.token.type == "string" || is("punc", ";") + ); + return S.token; + }; + + function prev() { + return S.prev; + }; + + function croak(msg, line, col, pos) { + var ctx = S.input.context(); + js_error(msg, + line != null ? line : ctx.tokline, + col != null ? col : ctx.tokcol, + pos != null ? pos : ctx.tokpos); + }; + + function token_error(token, msg) { + croak(msg, token.line, token.col); + }; + + function unexpected(token) { + if (token == null) + token = S.token; + token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); + }; + + function expect_token(type, val) { + if (is(type, val)) { + return next(); + } + token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type); + }; + + function expect(punc) { return expect_token("punc", punc); }; + + function can_insert_semicolon() { + return !exigent_mode && ( + S.token.nlb || is("eof") || is("punc", "}") + ); + }; + + function semicolon() { + if (is("punc", ";")) next(); + else if (!can_insert_semicolon()) unexpected(); + }; + + function as() { + return slice(arguments); + }; + + function parenthesised() { + expect("("); + var ex = expression(); + expect(")"); + return ex; + }; + + function add_tokens(str, start, end) { + return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end); + }; + + function maybe_embed_tokens(parser) { + if (embed_tokens) return function() { + var start = S.token; + var ast = parser.apply(this, arguments); + ast[0] = add_tokens(ast[0], start, prev()); + return ast; + }; + else return parser; + }; + + var statement = maybe_embed_tokens(function() { + if (is("operator", "/") || is("operator", "/=")) { + S.peeked = null; + S.token = S.input(S.token.value.substr(1)); // force regexp + } + switch (S.token.type) { + case "string": + var dir = S.in_directives, stat = simple_statement(); + if (dir && stat[1][0] == "string" && !is("punc", ",")) + return as("directive", stat[1][1]); + return stat; + case "num": + case "regexp": + case "operator": + case "atom": + return simple_statement(); + + case "name": + return is_token(peek(), "punc", ":") + ? labeled_statement(prog1(S.token.value, next, next)) + : simple_statement(); + + case "punc": + switch (S.token.value) { + case "{": + return as("block", block_()); + case "[": + case "(": + return simple_statement(); + case ";": + next(); + return as("block"); + default: + unexpected(); + } + + case "keyword": + switch (prog1(S.token.value, next)) { + case "break": + return break_cont("break"); + + case "continue": + return break_cont("continue"); + + case "debugger": + semicolon(); + return as("debugger"); + + case "do": + return (function(body){ + expect_token("keyword", "while"); + return as("do", prog1(parenthesised, semicolon), body); + })(in_loop(statement)); + + case "for": + return for_(); + + case "function": + return function_(true); + + case "if": + return if_(); + + case "return": + if (S.in_function == 0) + croak("'return' outside of function"); + return as("return", + is("punc", ";") + ? (next(), null) + : can_insert_semicolon() + ? null + : prog1(expression, semicolon)); + + case "switch": + return as("switch", parenthesised(), switch_block_()); + + case "throw": + if (S.token.nlb) + croak("Illegal newline after 'throw'"); + return as("throw", prog1(expression, semicolon)); + + case "try": + return try_(); + + case "var": + return prog1(var_, semicolon); + + case "const": + return prog1(const_, semicolon); + + case "while": + return as("while", parenthesised(), in_loop(statement)); + + case "with": + return as("with", parenthesised(), statement()); + + default: + unexpected(); + } + } + }); + + function labeled_statement(label) { + S.labels.push(label); + var start = S.token, stat = statement(); + if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) + unexpected(start); + S.labels.pop(); + return as("label", label, stat); + }; + + function simple_statement() { + return as("stat", prog1(expression, semicolon)); + }; + + function break_cont(type) { + var name; + if (!can_insert_semicolon()) { + name = is("name") ? S.token.value : null; + } + if (name != null) { + next(); + if (!member(name, S.labels)) + croak("Label " + name + " without matching loop or statement"); + } + else if (S.in_loop == 0) + croak(type + " not inside a loop or switch"); + semicolon(); + return as(type, name); + }; + + function for_() { + expect("("); + var init = null; + if (!is("punc", ";")) { + init = is("keyword", "var") + ? (next(), var_(true)) + : expression(true, true); + if (is("operator", "in")) { + if (init[0] == "var" && init[1].length > 1) + croak("Only one variable declaration allowed in for..in loop"); + return for_in(init); + } + } + return regular_for(init); + }; + + function regular_for(init) { + expect(";"); + var test = is("punc", ";") ? null : expression(); + expect(";"); + var step = is("punc", ")") ? null : expression(); + expect(")"); + return as("for", init, test, step, in_loop(statement)); + }; + + function for_in(init) { + var lhs = init[0] == "var" ? as("name", init[1][0]) : init; + next(); + var obj = expression(); + expect(")"); + return as("for-in", init, lhs, obj, in_loop(statement)); + }; + + var function_ = function(in_statement) { + var name = is("name") ? prog1(S.token.value, next) : null; + if (in_statement && !name) + unexpected(); + expect("("); + return as(in_statement ? "defun" : "function", + name, + // arguments + (function(first, a){ + while (!is("punc", ")")) { + if (first) first = false; else expect(","); + if (!is("name")) unexpected(); + a.push(S.token.value); + next(); + } + next(); + return a; + })(true, []), + // body + (function(){ + ++S.in_function; + var loop = S.in_loop; + S.in_directives = true; + S.in_loop = 0; + var a = block_(); + --S.in_function; + S.in_loop = loop; + return a; + })()); + }; + + function if_() { + var cond = parenthesised(), body = statement(), belse; + if (is("keyword", "else")) { + next(); + belse = statement(); + } + return as("if", cond, body, belse); + }; + + function block_() { + expect("{"); + var a = []; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + a.push(statement()); + } + next(); + return a; + }; + + var switch_block_ = curry(in_loop, function(){ + expect("{"); + var a = [], cur = null; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + if (is("keyword", "case")) { + next(); + cur = []; + a.push([ expression(), cur ]); + expect(":"); + } + else if (is("keyword", "default")) { + next(); + expect(":"); + cur = []; + a.push([ null, cur ]); + } + else { + if (!cur) unexpected(); + cur.push(statement()); + } + } + next(); + return a; + }); + + function try_() { + var body = block_(), bcatch, bfinally; + if (is("keyword", "catch")) { + next(); + expect("("); + if (!is("name")) + croak("Name expected"); + var name = S.token.value; + next(); + expect(")"); + bcatch = [ name, block_() ]; + } + if (is("keyword", "finally")) { + next(); + bfinally = block_(); + } + if (!bcatch && !bfinally) + croak("Missing catch/finally blocks"); + return as("try", body, bcatch, bfinally); + }; + + function vardefs(no_in) { + var a = []; + for (;;) { + if (!is("name")) + unexpected(); + var name = S.token.value; + next(); + if (is("operator", "=")) { + next(); + a.push([ name, expression(false, no_in) ]); + } else { + a.push([ name ]); + } + if (!is("punc", ",")) + break; + next(); + } + return a; + }; + + function var_(no_in) { + return as("var", vardefs(no_in)); + }; + + function const_() { + return as("const", vardefs()); + }; + + function new_() { + var newexp = expr_atom(false), args; + if (is("punc", "(")) { + next(); + args = expr_list(")"); + } else { + args = []; + } + return subscripts(as("new", newexp, args), true); + }; + + var expr_atom = maybe_embed_tokens(function(allow_calls) { + if (is("operator", "new")) { + next(); + return new_(); + } + if (is("punc")) { + switch (S.token.value) { + case "(": + next(); + return subscripts(prog1(expression, curry(expect, ")")), allow_calls); + case "[": + next(); + return subscripts(array_(), allow_calls); + case "{": + next(); + return subscripts(object_(), allow_calls); + } + unexpected(); + } + if (is("keyword", "function")) { + next(); + return subscripts(function_(false), allow_calls); + } + if (HOP(ATOMIC_START_TOKEN, S.token.type)) { + var atom = S.token.type == "regexp" + ? as("regexp", S.token.value[0], S.token.value[1]) + : as(S.token.type, S.token.value); + return subscripts(prog1(atom, next), allow_calls); + } + unexpected(); + }); + + function expr_list(closing, allow_trailing_comma, allow_empty) { + var first = true, a = []; + while (!is("punc", closing)) { + if (first) first = false; else expect(","); + if (allow_trailing_comma && is("punc", closing)) break; + if (is("punc", ",") && allow_empty) { + a.push([ "atom", "undefined" ]); + } else { + a.push(expression(false)); + } + } + next(); + return a; + }; + + function array_() { + return as("array", expr_list("]", !exigent_mode, true)); + }; + + function object_() { + var first = true, a = []; + while (!is("punc", "}")) { + if (first) first = false; else expect(","); + if (!exigent_mode && is("punc", "}")) + // allow trailing comma + break; + var type = S.token.type; + var name = as_property_name(); + if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) { + a.push([ as_name(), function_(false), name ]); + } else { + expect(":"); + a.push([ name, expression(false) ]); + } + } + next(); + return as("object", a); + }; + + function as_property_name() { + switch (S.token.type) { + case "num": + case "string": + return prog1(S.token.value, next); + } + return as_name(); + }; + + function as_name() { + switch (S.token.type) { + case "name": + case "operator": + case "keyword": + case "atom": + return prog1(S.token.value, next); + default: + unexpected(); + } + }; + + function subscripts(expr, allow_calls) { + if (is("punc", ".")) { + next(); + return subscripts(as("dot", expr, as_name()), allow_calls); + } + if (is("punc", "[")) { + next(); + return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls); + } + if (allow_calls && is("punc", "(")) { + next(); + return subscripts(as("call", expr, expr_list(")")), true); + } + return expr; + }; + + function maybe_unary(allow_calls) { + if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) { + return make_unary("unary-prefix", + prog1(S.token.value, next), + maybe_unary(allow_calls)); + } + var val = expr_atom(allow_calls); + while (is("operator") && HOP(UNARY_POSTFIX, S.token.value) && !S.token.nlb) { + val = make_unary("unary-postfix", S.token.value, val); + next(); + } + return val; + }; + + function make_unary(tag, op, expr) { + if ((op == "++" || op == "--") && !is_assignable(expr)) + croak("Invalid use of " + op + " operator"); + return as(tag, op, expr); + }; + + function expr_op(left, min_prec, no_in) { + var op = is("operator") ? S.token.value : null; + if (op && op == "in" && no_in) op = null; + var prec = op != null ? PRECEDENCE[op] : null; + if (prec != null && prec > min_prec) { + next(); + var right = expr_op(maybe_unary(true), prec, no_in); + return expr_op(as("binary", op, left, right), min_prec, no_in); + } + return left; + }; + + function expr_ops(no_in) { + return expr_op(maybe_unary(true), 0, no_in); + }; + + function maybe_conditional(no_in) { + var expr = expr_ops(no_in); + if (is("operator", "?")) { + next(); + var yes = expression(false); + expect(":"); + return as("conditional", expr, yes, expression(false, no_in)); + } + return expr; + }; + + function is_assignable(expr) { + if (!exigent_mode) return true; + switch (expr[0]+"") { + case "dot": + case "sub": + case "new": + case "call": + return true; + case "name": + return expr[1] != "this"; + } + }; + + function maybe_assign(no_in) { + var left = maybe_conditional(no_in), val = S.token.value; + if (is("operator") && HOP(ASSIGNMENT, val)) { + if (is_assignable(left)) { + next(); + return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in)); + } + croak("Invalid assignment"); + } + return left; + }; + + var expression = maybe_embed_tokens(function(commas, no_in) { + if (arguments.length == 0) + commas = true; + var expr = maybe_assign(no_in); + if (commas && is("punc", ",")) { + next(); + return as("seq", expr, expression(true, no_in)); + } + return expr; + }); + + function in_loop(cont) { + try { + ++S.in_loop; + return cont(); + } finally { + --S.in_loop; + } + }; + + return as("toplevel", (function(a){ + while (!is("eof")) + a.push(statement()); + return a; + })([])); + +}; + +/* -----[ Utilities ]----- */ + +function curry(f) { + var args = slice(arguments, 1); + return function() { return f.apply(this, args.concat(slice(arguments))); }; +}; + +function prog1(ret) { + if (ret instanceof Function) + ret = ret(); + for (var i = 1, n = arguments.length; --n > 0; ++i) + arguments[i](); + return ret; +}; + +function array_to_hash(a) { + var ret = {}; + for (var i = 0; i < a.length; ++i) + ret[a[i]] = true; + return ret; +}; + +function slice(a, start) { + return Array.prototype.slice.call(a, start || 0); +}; + +function characters(str) { + return str.split(""); +}; + +function member(name, array) { + for (var i = array.length; --i >= 0;) + if (array[i] == name) + return true; + return false; +}; + +function HOP(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +}; + +var warn = function() {}; + +/* -----[ Exports ]----- */ + +exports.tokenizer = tokenizer; +exports.parse = parse; +exports.slice = slice; +exports.curry = curry; +exports.member = member; +exports.array_to_hash = array_to_hash; +exports.PRECEDENCE = PRECEDENCE; +exports.KEYWORDS_ATOM = KEYWORDS_ATOM; +exports.RESERVED_WORDS = RESERVED_WORDS; +exports.KEYWORDS = KEYWORDS; +exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN; +exports.OPERATORS = OPERATORS; +exports.is_alphanumeric_char = is_alphanumeric_char; +exports.is_identifier_start = is_identifier_start; +exports.is_identifier_char = is_identifier_char; +exports.set_logger = function(logger) { + warn = logger; +}; + +// Local variables: +// js-indent-level: 4 +// End: +});define('uglifyjs/squeeze-more', ["require", "exports", "module", "./parse-js", "./squeeze-more"], function(require, exports, module) { +var jsp = require("./parse-js"), + pro = require("./process"), + slice = jsp.slice, + member = jsp.member, + curry = jsp.curry, + MAP = pro.MAP, + PRECEDENCE = jsp.PRECEDENCE, + OPERATORS = jsp.OPERATORS; + +function ast_squeeze_more(ast) { + var w = pro.ast_walker(), walk = w.walk, scope; + function with_scope(s, cont) { + var save = scope, ret; + scope = s; + ret = cont(); + scope = save; + return ret; + }; + function _lambda(name, args, body) { + return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ]; + }; + return w.with_walkers({ + "toplevel": function(body) { + return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ]; + }, + "function": _lambda, + "defun": _lambda, + "new": function(ctor, args) { + if (ctor[0] == "name") { + if (ctor[1] == "Array" && !scope.has("Array")) { + if (args.length != 1) { + return [ "array", args ]; + } else { + return walk([ "call", [ "name", "Array" ], args ]); + } + } else if (ctor[1] == "Object" && !scope.has("Object")) { + if (!args.length) { + return [ "object", [] ]; + } else { + return walk([ "call", [ "name", "Object" ], args ]); + } + } else if ((ctor[1] == "RegExp" || ctor[1] == "Function" || ctor[1] == "Error") && !scope.has(ctor[1])) { + return walk([ "call", [ "name", ctor[1] ], args]); + } + } + }, + "call": function(expr, args) { + if (expr[0] == "dot" && expr[1][0] == "string" && args.length == 1 + && (args[0][1] > 0 && expr[2] == "substring" || expr[2] == "substr")) { + return [ "call", [ "dot", expr[1], "slice"], args]; + } + if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) { + // foo.toString() ==> foo+"" + if (expr[1][0] == "string") return expr[1]; + return [ "binary", "+", expr[1], [ "string", "" ]]; + } + if (expr[0] == "name") { + if (expr[1] == "Array" && args.length != 1 && !scope.has("Array")) { + return [ "array", args ]; + } + if (expr[1] == "Object" && !args.length && !scope.has("Object")) { + return [ "object", [] ]; + } + if (expr[1] == "String" && !scope.has("String")) { + return [ "binary", "+", args[0], [ "string", "" ]]; + } + } + } + }, function() { + return walk(pro.ast_add_scope(ast)); + }); +}; + +exports.ast_squeeze_more = ast_squeeze_more; + +// Local variables: +// js-indent-level: 4 +// End: +}); +define('uglifyjs/process', ["require", "exports", "module", "./parse-js", "./squeeze-more"], function(require, exports, module) { +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + + This version is suitable for Node.js. With minimal changes (the + exports stuff) it should work on any JS platform. + + This file implements some AST processors. They work on data built + by parse-js. + + Exported functions: + + - ast_mangle(ast, options) -- mangles the variable/function names + in the AST. Returns an AST. + + - ast_squeeze(ast) -- employs various optimizations to make the + final generated code even smaller. Returns an AST. + + - gen_code(ast, options) -- generates JS code from the AST. Pass + true (or an object, see the code for some options) as second + argument to get "pretty" (indented) code. + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2010 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +var jsp = require("./parse-js"), + curry = jsp.curry, + slice = jsp.slice, + member = jsp.member, + is_identifier_char = jsp.is_identifier_char, + PRECEDENCE = jsp.PRECEDENCE, + OPERATORS = jsp.OPERATORS; + +/* -----[ helper for AST traversal ]----- */ + +function ast_walker() { + function _vardefs(defs) { + return [ this[0], MAP(defs, function(def){ + var a = [ def[0] ]; + if (def.length > 1) + a[1] = walk(def[1]); + return a; + }) ]; + }; + function _block(statements) { + var out = [ this[0] ]; + if (statements != null) + out.push(MAP(statements, walk)); + return out; + }; + var walkers = { + "string": function(str) { + return [ this[0], str ]; + }, + "num": function(num) { + return [ this[0], num ]; + }, + "name": function(name) { + return [ this[0], name ]; + }, + "toplevel": function(statements) { + return [ this[0], MAP(statements, walk) ]; + }, + "block": _block, + "splice": _block, + "var": _vardefs, + "const": _vardefs, + "try": function(t, c, f) { + return [ + this[0], + MAP(t, walk), + c != null ? [ c[0], MAP(c[1], walk) ] : null, + f != null ? MAP(f, walk) : null + ]; + }, + "throw": function(expr) { + return [ this[0], walk(expr) ]; + }, + "new": function(ctor, args) { + return [ this[0], walk(ctor), MAP(args, walk) ]; + }, + "switch": function(expr, body) { + return [ this[0], walk(expr), MAP(body, function(branch){ + return [ branch[0] ? walk(branch[0]) : null, + MAP(branch[1], walk) ]; + }) ]; + }, + "break": function(label) { + return [ this[0], label ]; + }, + "continue": function(label) { + return [ this[0], label ]; + }, + "conditional": function(cond, t, e) { + return [ this[0], walk(cond), walk(t), walk(e) ]; + }, + "assign": function(op, lvalue, rvalue) { + return [ this[0], op, walk(lvalue), walk(rvalue) ]; + }, + "dot": function(expr) { + return [ this[0], walk(expr) ].concat(slice(arguments, 1)); + }, + "call": function(expr, args) { + return [ this[0], walk(expr), MAP(args, walk) ]; + }, + "function": function(name, args, body) { + return [ this[0], name, args.slice(), MAP(body, walk) ]; + }, + "debugger": function() { + return [ this[0] ]; + }, + "defun": function(name, args, body) { + return [ this[0], name, args.slice(), MAP(body, walk) ]; + }, + "if": function(conditional, t, e) { + return [ this[0], walk(conditional), walk(t), walk(e) ]; + }, + "for": function(init, cond, step, block) { + return [ this[0], walk(init), walk(cond), walk(step), walk(block) ]; + }, + "for-in": function(vvar, key, hash, block) { + return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ]; + }, + "while": function(cond, block) { + return [ this[0], walk(cond), walk(block) ]; + }, + "do": function(cond, block) { + return [ this[0], walk(cond), walk(block) ]; + }, + "return": function(expr) { + return [ this[0], walk(expr) ]; + }, + "binary": function(op, left, right) { + return [ this[0], op, walk(left), walk(right) ]; + }, + "unary-prefix": function(op, expr) { + return [ this[0], op, walk(expr) ]; + }, + "unary-postfix": function(op, expr) { + return [ this[0], op, walk(expr) ]; + }, + "sub": function(expr, subscript) { + return [ this[0], walk(expr), walk(subscript) ]; + }, + "object": function(props) { + return [ this[0], MAP(props, function(p){ + return p.length == 2 + ? [ p[0], walk(p[1]) ] + : [ p[0], walk(p[1]), p[2] ]; // get/set-ter + }) ]; + }, + "regexp": function(rx, mods) { + return [ this[0], rx, mods ]; + }, + "array": function(elements) { + return [ this[0], MAP(elements, walk) ]; + }, + "stat": function(stat) { + return [ this[0], walk(stat) ]; + }, + "seq": function() { + return [ this[0] ].concat(MAP(slice(arguments), walk)); + }, + "label": function(name, block) { + return [ this[0], name, walk(block) ]; + }, + "with": function(expr, block) { + return [ this[0], walk(expr), walk(block) ]; + }, + "atom": function(name) { + return [ this[0], name ]; + }, + "directive": function(dir) { + return [ this[0], dir ]; + } + }; + + var user = {}; + var stack = []; + function walk(ast) { + if (ast == null) + return null; + try { + stack.push(ast); + var type = ast[0]; + var gen = user[type]; + if (gen) { + var ret = gen.apply(ast, ast.slice(1)); + if (ret != null) + return ret; + } + gen = walkers[type]; + return gen.apply(ast, ast.slice(1)); + } finally { + stack.pop(); + } + }; + + function dive(ast) { + if (ast == null) + return null; + try { + stack.push(ast); + return walkers[ast[0]].apply(ast, ast.slice(1)); + } finally { + stack.pop(); + } + }; + + function with_walkers(walkers, cont){ + var save = {}, i; + for (i in walkers) if (HOP(walkers, i)) { + save[i] = user[i]; + user[i] = walkers[i]; + } + var ret = cont(); + for (i in save) if (HOP(save, i)) { + if (!save[i]) delete user[i]; + else user[i] = save[i]; + } + return ret; + }; + + return { + walk: walk, + dive: dive, + with_walkers: with_walkers, + parent: function() { + return stack[stack.length - 2]; // last one is current node + }, + stack: function() { + return stack; + } + }; +}; + +/* -----[ Scope and mangling ]----- */ + +function Scope(parent) { + this.names = {}; // names defined in this scope + this.mangled = {}; // mangled names (orig.name => mangled) + this.rev_mangled = {}; // reverse lookup (mangled => orig.name) + this.cname = -1; // current mangled name + this.refs = {}; // names referenced from this scope + this.uses_with = false; // will become TRUE if with() is detected in this or any subscopes + this.uses_eval = false; // will become TRUE if eval() is detected in this or any subscopes + this.directives = []; // directives activated from this scope + this.parent = parent; // parent scope + this.children = []; // sub-scopes + if (parent) { + this.level = parent.level + 1; + parent.children.push(this); + } else { + this.level = 0; + } +}; + +function base54_digits() { + if (typeof DIGITS_OVERRIDE_FOR_TESTING != "undefined") + return DIGITS_OVERRIDE_FOR_TESTING; + else + return "etnrisouaflchpdvmgybwESxTNCkLAOM_DPHBjFIqRUzWXV$JKQGYZ0516372984"; +} + +var base54 = (function(){ + var DIGITS = base54_digits(); + return function(num) { + var ret = "", base = 54; + do { + ret += DIGITS.charAt(num % base); + num = Math.floor(num / base); + base = 64; + } while (num > 0); + return ret; + }; +})(); + +Scope.prototype = { + has: function(name) { + for (var s = this; s; s = s.parent) + if (HOP(s.names, name)) + return s; + }, + has_mangled: function(mname) { + for (var s = this; s; s = s.parent) + if (HOP(s.rev_mangled, mname)) + return s; + }, + toJSON: function() { + return { + names: this.names, + uses_eval: this.uses_eval, + uses_with: this.uses_with + }; + }, + + next_mangled: function() { + // we must be careful that the new mangled name: + // + // 1. doesn't shadow a mangled name from a parent + // scope, unless we don't reference the original + // name from this scope OR from any sub-scopes! + // This will get slow. + // + // 2. doesn't shadow an original name from a parent + // scope, in the event that the name is not mangled + // in the parent scope and we reference that name + // here OR IN ANY SUBSCOPES! + // + // 3. doesn't shadow a name that is referenced but not + // defined (possibly global defined elsewhere). + for (;;) { + var m = base54(++this.cname), prior; + + // case 1. + prior = this.has_mangled(m); + if (prior && this.refs[prior.rev_mangled[m]] === prior) + continue; + + // case 2. + prior = this.has(m); + if (prior && prior !== this && this.refs[m] === prior && !prior.has_mangled(m)) + continue; + + // case 3. + if (HOP(this.refs, m) && this.refs[m] == null) + continue; + + // I got "do" once. :-/ + if (!is_identifier(m)) + continue; + + return m; + } + }, + set_mangle: function(name, m) { + this.rev_mangled[m] = name; + return this.mangled[name] = m; + }, + get_mangled: function(name, newMangle) { + if (this.uses_eval || this.uses_with) return name; // no mangle if eval or with is in use + var s = this.has(name); + if (!s) return name; // not in visible scope, no mangle + if (HOP(s.mangled, name)) return s.mangled[name]; // already mangled in this scope + if (!newMangle) return name; // not found and no mangling requested + return s.set_mangle(name, s.next_mangled()); + }, + references: function(name) { + return name && !this.parent || this.uses_with || this.uses_eval || this.refs[name]; + }, + define: function(name, type) { + if (name != null) { + if (type == "var" || !HOP(this.names, name)) + this.names[name] = type || "var"; + return name; + } + }, + active_directive: function(dir) { + return member(dir, this.directives) || this.parent && this.parent.active_directive(dir); + } +}; + +function ast_add_scope(ast) { + + var current_scope = null; + var w = ast_walker(), walk = w.walk; + var having_eval = []; + + function with_new_scope(cont) { + current_scope = new Scope(current_scope); + current_scope.labels = new Scope(); + var ret = current_scope.body = cont(); + ret.scope = current_scope; + current_scope = current_scope.parent; + return ret; + }; + + function define(name, type) { + return current_scope.define(name, type); + }; + + function reference(name) { + current_scope.refs[name] = true; + }; + + function _lambda(name, args, body) { + var is_defun = this[0] == "defun"; + return [ this[0], is_defun ? define(name, "defun") : name, args, with_new_scope(function(){ + if (!is_defun) define(name, "lambda"); + MAP(args, function(name){ define(name, "arg") }); + return MAP(body, walk); + })]; + }; + + function _vardefs(type) { + return function(defs) { + MAP(defs, function(d){ + define(d[0], type); + if (d[1]) reference(d[0]); + }); + }; + }; + + function _breacont(label) { + if (label) + current_scope.labels.refs[label] = true; + }; + + return with_new_scope(function(){ + // process AST + var ret = w.with_walkers({ + "function": _lambda, + "defun": _lambda, + "label": function(name, stat) { current_scope.labels.define(name) }, + "break": _breacont, + "continue": _breacont, + "with": function(expr, block) { + for (var s = current_scope; s; s = s.parent) + s.uses_with = true; + }, + "var": _vardefs("var"), + "const": _vardefs("const"), + "try": function(t, c, f) { + if (c != null) return [ + this[0], + MAP(t, walk), + [ define(c[0], "catch"), MAP(c[1], walk) ], + f != null ? MAP(f, walk) : null + ]; + }, + "name": function(name) { + if (name == "eval") + having_eval.push(current_scope); + reference(name); + } + }, function(){ + return walk(ast); + }); + + // the reason why we need an additional pass here is + // that names can be used prior to their definition. + + // scopes where eval was detected and their parents + // are marked with uses_eval, unless they define the + // "eval" name. + MAP(having_eval, function(scope){ + if (!scope.has("eval")) while (scope) { + scope.uses_eval = true; + scope = scope.parent; + } + }); + + // for referenced names it might be useful to know + // their origin scope. current_scope here is the + // toplevel one. + function fixrefs(scope, i) { + // do children first; order shouldn't matter + for (i = scope.children.length; --i >= 0;) + fixrefs(scope.children[i]); + for (i in scope.refs) if (HOP(scope.refs, i)) { + // find origin scope and propagate the reference to origin + for (var origin = scope.has(i), s = scope; s; s = s.parent) { + s.refs[i] = origin; + if (s === origin) break; + } + } + }; + fixrefs(current_scope); + + return ret; + }); + +}; + +/* -----[ mangle names ]----- */ + +function ast_mangle(ast, options) { + var w = ast_walker(), walk = w.walk, scope; + options = defaults(options, { + mangle : true, + toplevel : false, + defines : null, + except : null, + no_functions : false + }); + + function get_mangled(name, newMangle) { + if (!options.mangle) return name; + if (!options.toplevel && !scope.parent) return name; // don't mangle toplevel + if (options.except && member(name, options.except)) + return name; + if (options.no_functions && HOP(scope.names, name) && + (scope.names[name] == 'defun' || scope.names[name] == 'lambda')) + return name; + return scope.get_mangled(name, newMangle); + }; + + function get_define(name) { + if (options.defines) { + // we always lookup a defined symbol for the current scope FIRST, so declared + // vars trump a DEFINE symbol, but if no such var is found, then match a DEFINE value + if (!scope.has(name)) { + if (HOP(options.defines, name)) { + return options.defines[name]; + } + } + return null; + } + }; + + function _lambda(name, args, body) { + if (!options.no_functions && options.mangle) { + var is_defun = this[0] == "defun", extra; + if (name) { + if (is_defun) name = get_mangled(name); + else if (body.scope.references(name)) { + extra = {}; + if (!(scope.uses_eval || scope.uses_with)) + name = extra[name] = scope.next_mangled(); + else + extra[name] = name; + } + else name = null; + } + } + body = with_scope(body.scope, function(){ + args = MAP(args, function(name){ return get_mangled(name) }); + return MAP(body, walk); + }, extra); + return [ this[0], name, args, body ]; + }; + + function with_scope(s, cont, extra) { + var _scope = scope; + scope = s; + if (extra) for (var i in extra) if (HOP(extra, i)) { + s.set_mangle(i, extra[i]); + } + for (var i in s.names) if (HOP(s.names, i)) { + get_mangled(i, true); + } + var ret = cont(); + ret.scope = s; + scope = _scope; + return ret; + }; + + function _vardefs(defs) { + return [ this[0], MAP(defs, function(d){ + return [ get_mangled(d[0]), walk(d[1]) ]; + }) ]; + }; + + function _breacont(label) { + if (label) return [ this[0], scope.labels.get_mangled(label) ]; + }; + + return w.with_walkers({ + "function": _lambda, + "defun": function() { + // move function declarations to the top when + // they are not in some block. + var ast = _lambda.apply(this, arguments); + switch (w.parent()[0]) { + case "toplevel": + case "function": + case "defun": + return MAP.at_top(ast); + } + return ast; + }, + "label": function(label, stat) { + if (scope.labels.refs[label]) return [ + this[0], + scope.labels.get_mangled(label, true), + walk(stat) + ]; + return walk(stat); + }, + "break": _breacont, + "continue": _breacont, + "var": _vardefs, + "const": _vardefs, + "name": function(name) { + return get_define(name) || [ this[0], get_mangled(name) ]; + }, + "try": function(t, c, f) { + return [ this[0], + MAP(t, walk), + c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null, + f != null ? MAP(f, walk) : null ]; + }, + "toplevel": function(body) { + var self = this; + return with_scope(self.scope, function(){ + return [ self[0], MAP(body, walk) ]; + }); + }, + "directive": function() { + return MAP.at_top(this); + } + }, function() { + return walk(ast_add_scope(ast)); + }); +}; + +/* -----[ + - compress foo["bar"] into foo.bar, + - remove block brackets {} where possible + - join consecutive var declarations + - various optimizations for IFs: + - if (cond) foo(); else bar(); ==> cond?foo():bar(); + - if (cond) foo(); ==> cond&&foo(); + - if (foo) return bar(); else return baz(); ==> return foo?bar():baz(); // also for throw + - if (foo) return bar(); else something(); ==> {if(foo)return bar();something()} + ]----- */ + +var warn = function(){}; + +function best_of(ast1, ast2) { + return gen_code(ast1).length > gen_code(ast2[0] == "stat" ? ast2[1] : ast2).length ? ast2 : ast1; +}; + +function last_stat(b) { + if (b[0] == "block" && b[1] && b[1].length > 0) + return b[1][b[1].length - 1]; + return b; +} + +function aborts(t) { + if (t) switch (last_stat(t)[0]) { + case "return": + case "break": + case "continue": + case "throw": + return true; + } +}; + +function boolean_expr(expr) { + return ( (expr[0] == "unary-prefix" + && member(expr[1], [ "!", "delete" ])) || + + (expr[0] == "binary" + && member(expr[1], [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ])) || + + (expr[0] == "binary" + && member(expr[1], [ "&&", "||" ]) + && boolean_expr(expr[2]) + && boolean_expr(expr[3])) || + + (expr[0] == "conditional" + && boolean_expr(expr[2]) + && boolean_expr(expr[3])) || + + (expr[0] == "assign" + && expr[1] === true + && boolean_expr(expr[3])) || + + (expr[0] == "seq" + && boolean_expr(expr[expr.length - 1])) + ); +}; + +function empty(b) { + return !b || (b[0] == "block" && (!b[1] || b[1].length == 0)); +}; + +function is_string(node) { + return (node[0] == "string" || + node[0] == "unary-prefix" && node[1] == "typeof" || + node[0] == "binary" && node[1] == "+" && + (is_string(node[2]) || is_string(node[3]))); +}; + +var when_constant = (function(){ + + var $NOT_CONSTANT = {}; + + // this can only evaluate constant expressions. If it finds anything + // not constant, it throws $NOT_CONSTANT. + function evaluate(expr) { + switch (expr[0]) { + case "string": + case "num": + return expr[1]; + case "name": + case "atom": + switch (expr[1]) { + case "true": return true; + case "false": return false; + case "null": return null; + } + break; + case "unary-prefix": + switch (expr[1]) { + case "!": return !evaluate(expr[2]); + case "typeof": return typeof evaluate(expr[2]); + case "~": return ~evaluate(expr[2]); + case "-": return -evaluate(expr[2]); + case "+": return +evaluate(expr[2]); + } + break; + case "binary": + var left = expr[2], right = expr[3]; + switch (expr[1]) { + case "&&" : return evaluate(left) && evaluate(right); + case "||" : return evaluate(left) || evaluate(right); + case "|" : return evaluate(left) | evaluate(right); + case "&" : return evaluate(left) & evaluate(right); + case "^" : return evaluate(left) ^ evaluate(right); + case "+" : return evaluate(left) + evaluate(right); + case "*" : return evaluate(left) * evaluate(right); + case "/" : return evaluate(left) / evaluate(right); + case "%" : return evaluate(left) % evaluate(right); + case "-" : return evaluate(left) - evaluate(right); + case "<<" : return evaluate(left) << evaluate(right); + case ">>" : return evaluate(left) >> evaluate(right); + case ">>>" : return evaluate(left) >>> evaluate(right); + case "==" : return evaluate(left) == evaluate(right); + case "===" : return evaluate(left) === evaluate(right); + case "!=" : return evaluate(left) != evaluate(right); + case "!==" : return evaluate(left) !== evaluate(right); + case "<" : return evaluate(left) < evaluate(right); + case "<=" : return evaluate(left) <= evaluate(right); + case ">" : return evaluate(left) > evaluate(right); + case ">=" : return evaluate(left) >= evaluate(right); + case "in" : return evaluate(left) in evaluate(right); + case "instanceof" : return evaluate(left) instanceof evaluate(right); + } + } + throw $NOT_CONSTANT; + }; + + return function(expr, yes, no) { + try { + var val = evaluate(expr), ast; + switch (typeof val) { + case "string": ast = [ "string", val ]; break; + case "number": ast = [ "num", val ]; break; + case "boolean": ast = [ "name", String(val) ]; break; + default: + if (val === null) { ast = [ "atom", "null" ]; break; } + throw new Error("Can't handle constant of type: " + (typeof val)); + } + return yes.call(expr, ast, val); + } catch(ex) { + if (ex === $NOT_CONSTANT) { + if (expr[0] == "binary" + && (expr[1] == "===" || expr[1] == "!==") + && ((is_string(expr[2]) && is_string(expr[3])) + || (boolean_expr(expr[2]) && boolean_expr(expr[3])))) { + expr[1] = expr[1].substr(0, 2); + } + else if (no && expr[0] == "binary" + && (expr[1] == "||" || expr[1] == "&&")) { + // the whole expression is not constant but the lval may be... + try { + var lval = evaluate(expr[2]); + expr = ((expr[1] == "&&" && (lval ? expr[3] : lval)) || + (expr[1] == "||" && (lval ? lval : expr[3])) || + expr); + } catch(ex2) { + // IGNORE... lval is not constant + } + } + return no ? no.call(expr, expr) : null; + } + else throw ex; + } + }; + +})(); + +function warn_unreachable(ast) { + if (!empty(ast)) + warn("Dropping unreachable code: " + gen_code(ast, true)); +}; + +function prepare_ifs(ast) { + var w = ast_walker(), walk = w.walk; + // In this first pass, we rewrite ifs which abort with no else with an + // if-else. For example: + // + // if (x) { + // blah(); + // return y; + // } + // foobar(); + // + // is rewritten into: + // + // if (x) { + // blah(); + // return y; + // } else { + // foobar(); + // } + function redo_if(statements) { + statements = MAP(statements, walk); + + for (var i = 0; i < statements.length; ++i) { + var fi = statements[i]; + if (fi[0] != "if") continue; + + if (fi[3]) continue; + + var t = fi[2]; + if (!aborts(t)) continue; + + var conditional = walk(fi[1]); + + var e_body = redo_if(statements.slice(i + 1)); + var e = e_body.length == 1 ? e_body[0] : [ "block", e_body ]; + + return statements.slice(0, i).concat([ [ + fi[0], // "if" + conditional, // conditional + t, // then + e // else + ] ]); + } + + return statements; + }; + + function redo_if_lambda(name, args, body) { + body = redo_if(body); + return [ this[0], name, args, body ]; + }; + + function redo_if_block(statements) { + return [ this[0], statements != null ? redo_if(statements) : null ]; + }; + + return w.with_walkers({ + "defun": redo_if_lambda, + "function": redo_if_lambda, + "block": redo_if_block, + "splice": redo_if_block, + "toplevel": function(statements) { + return [ this[0], redo_if(statements) ]; + }, + "try": function(t, c, f) { + return [ + this[0], + redo_if(t), + c != null ? [ c[0], redo_if(c[1]) ] : null, + f != null ? redo_if(f) : null + ]; + } + }, function() { + return walk(ast); + }); +}; + +function for_side_effects(ast, handler) { + var w = ast_walker(), walk = w.walk; + var $stop = {}, $restart = {}; + function stop() { throw $stop }; + function restart() { throw $restart }; + function found(){ return handler.call(this, this, w, stop, restart) }; + function unary(op) { + if (op == "++" || op == "--") + return found.apply(this, arguments); + }; + function binary(op) { + if (op == "&&" || op == "||") + return found.apply(this, arguments); + }; + return w.with_walkers({ + "try": found, + "throw": found, + "return": found, + "new": found, + "switch": found, + "break": found, + "continue": found, + "assign": found, + "call": found, + "if": found, + "for": found, + "for-in": found, + "while": found, + "do": found, + "return": found, + "unary-prefix": unary, + "unary-postfix": unary, + "conditional": found, + "binary": binary, + "defun": found + }, function(){ + while (true) try { + walk(ast); + break; + } catch(ex) { + if (ex === $stop) break; + if (ex === $restart) continue; + throw ex; + } + }); +}; + +function ast_lift_variables(ast) { + var w = ast_walker(), walk = w.walk, scope; + function do_body(body, env) { + var _scope = scope; + scope = env; + body = MAP(body, walk); + var hash = {}, names = MAP(env.names, function(type, name){ + if (type != "var") return MAP.skip; + if (!env.references(name)) return MAP.skip; + hash[name] = true; + return [ name ]; + }); + if (names.length > 0) { + // looking for assignments to any of these variables. + // we can save considerable space by moving the definitions + // in the var declaration. + for_side_effects([ "block", body ], function(ast, walker, stop, restart) { + if (ast[0] == "assign" + && ast[1] === true + && ast[2][0] == "name" + && HOP(hash, ast[2][1])) { + // insert the definition into the var declaration + for (var i = names.length; --i >= 0;) { + if (names[i][0] == ast[2][1]) { + if (names[i][1]) // this name already defined, we must stop + stop(); + names[i][1] = ast[3]; // definition + names.push(names.splice(i, 1)[0]); + break; + } + } + // remove this assignment from the AST. + var p = walker.parent(); + if (p[0] == "seq") { + var a = p[2]; + a.unshift(0, p.length); + p.splice.apply(p, a); + } + else if (p[0] == "stat") { + p.splice(0, p.length, "block"); // empty statement + } + else { + stop(); + } + restart(); + } + stop(); + }); + body.unshift([ "var", names ]); + } + scope = _scope; + return body; + }; + function _vardefs(defs) { + var ret = null; + for (var i = defs.length; --i >= 0;) { + var d = defs[i]; + if (!d[1]) continue; + d = [ "assign", true, [ "name", d[0] ], d[1] ]; + if (ret == null) ret = d; + else ret = [ "seq", d, ret ]; + } + if (ret == null && w.parent()[0] != "for") { + if (w.parent()[0] == "for-in") + return [ "name", defs[0][0] ]; + return MAP.skip; + } + return [ "stat", ret ]; + }; + function _toplevel(body) { + return [ this[0], do_body(body, this.scope) ]; + }; + return w.with_walkers({ + "function": function(name, args, body){ + for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);) + args.pop(); + if (!body.scope.references(name)) name = null; + return [ this[0], name, args, do_body(body, body.scope) ]; + }, + "defun": function(name, args, body){ + if (!scope.references(name)) return MAP.skip; + for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);) + args.pop(); + return [ this[0], name, args, do_body(body, body.scope) ]; + }, + "var": _vardefs, + "toplevel": _toplevel + }, function(){ + return walk(ast_add_scope(ast)); + }); +}; + +function ast_squeeze(ast, options) { + ast = squeeze_1(ast, options); + ast = squeeze_2(ast, options); + return ast; +}; + +function squeeze_1(ast, options) { + options = defaults(options, { + make_seqs : true, + dead_code : true, + no_warnings : false, + keep_comps : true, + unsafe : false + }); + + var w = ast_walker(), walk = w.walk, scope; + + function negate(c) { + var not_c = [ "unary-prefix", "!", c ]; + switch (c[0]) { + case "unary-prefix": + return c[1] == "!" && boolean_expr(c[2]) ? c[2] : not_c; + case "seq": + c = slice(c); + c[c.length - 1] = negate(c[c.length - 1]); + return c; + case "conditional": + return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]); + case "binary": + var op = c[1], left = c[2], right = c[3]; + if (!options.keep_comps) switch (op) { + case "<=" : return [ "binary", ">", left, right ]; + case "<" : return [ "binary", ">=", left, right ]; + case ">=" : return [ "binary", "<", left, right ]; + case ">" : return [ "binary", "<=", left, right ]; + } + switch (op) { + case "==" : return [ "binary", "!=", left, right ]; + case "!=" : return [ "binary", "==", left, right ]; + case "===" : return [ "binary", "!==", left, right ]; + case "!==" : return [ "binary", "===", left, right ]; + case "&&" : return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]); + case "||" : return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]); + } + break; + } + return not_c; + }; + + function make_conditional(c, t, e) { + var make_real_conditional = function() { + if (c[0] == "unary-prefix" && c[1] == "!") { + return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ]; + } else { + return e ? best_of( + [ "conditional", c, t, e ], + [ "conditional", negate(c), e, t ] + ) : [ "binary", "&&", c, t ]; + } + }; + // shortcut the conditional if the expression has a constant value + return when_constant(c, function(ast, val){ + warn_unreachable(val ? e : t); + return (val ? t : e); + }, make_real_conditional); + }; + + function rmblock(block) { + if (block != null && block[0] == "block" && block[1]) { + if (block[1].length == 1) + block = block[1][0]; + else if (block[1].length == 0) + block = [ "block" ]; + } + return block; + }; + + function _lambda(name, args, body) { + return [ this[0], name, args, tighten(body, "lambda") ]; + }; + + // this function does a few things: + // 1. discard useless blocks + // 2. join consecutive var declarations + // 3. remove obviously dead code + // 4. transform consecutive statements using the comma operator + // 5. if block_type == "lambda" and it detects constructs like if(foo) return ... - rewrite like if (!foo) { ... } + function tighten(statements, block_type) { + statements = MAP(statements, walk); + + statements = statements.reduce(function(a, stat){ + if (stat[0] == "block") { + if (stat[1]) { + a.push.apply(a, stat[1]); + } + } else { + a.push(stat); + } + return a; + }, []); + + statements = (function(a, prev){ + statements.forEach(function(cur){ + if (prev && ((cur[0] == "var" && prev[0] == "var") || + (cur[0] == "const" && prev[0] == "const"))) { + prev[1] = prev[1].concat(cur[1]); + } else { + a.push(cur); + prev = cur; + } + }); + return a; + })([]); + + if (options.dead_code) statements = (function(a, has_quit){ + statements.forEach(function(st){ + if (has_quit) { + if (st[0] == "function" || st[0] == "defun") { + a.push(st); + } + else if (st[0] == "var" || st[0] == "const") { + if (!options.no_warnings) + warn("Variables declared in unreachable code"); + st[1] = MAP(st[1], function(def){ + if (def[1] && !options.no_warnings) + warn_unreachable([ "assign", true, [ "name", def[0] ], def[1] ]); + return [ def[0] ]; + }); + a.push(st); + } + else if (!options.no_warnings) + warn_unreachable(st); + } + else { + a.push(st); + if (member(st[0], [ "return", "throw", "break", "continue" ])) + has_quit = true; + } + }); + return a; + })([]); + + if (options.make_seqs) statements = (function(a, prev) { + statements.forEach(function(cur){ + if (prev && prev[0] == "stat" && cur[0] == "stat") { + prev[1] = [ "seq", prev[1], cur[1] ]; + } else { + a.push(cur); + prev = cur; + } + }); + if (a.length >= 2 + && a[a.length-2][0] == "stat" + && (a[a.length-1][0] == "return" || a[a.length-1][0] == "throw") + && a[a.length-1][1]) + { + a.splice(a.length - 2, 2, + [ a[a.length-1][0], + [ "seq", a[a.length-2][1], a[a.length-1][1] ]]); + } + return a; + })([]); + + // this increases jQuery by 1K. Probably not such a good idea after all.. + // part of this is done in prepare_ifs anyway. + // if (block_type == "lambda") statements = (function(i, a, stat){ + // while (i < statements.length) { + // stat = statements[i++]; + // if (stat[0] == "if" && !stat[3]) { + // if (stat[2][0] == "return" && stat[2][1] == null) { + // a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ])); + // break; + // } + // var last = last_stat(stat[2]); + // if (last[0] == "return" && last[1] == null) { + // a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ])); + // break; + // } + // } + // a.push(stat); + // } + // return a; + // })(0, []); + + return statements; + }; + + function make_if(c, t, e) { + return when_constant(c, function(ast, val){ + if (val) { + t = walk(t); + warn_unreachable(e); + return t || [ "block" ]; + } else { + e = walk(e); + warn_unreachable(t); + return e || [ "block" ]; + } + }, function() { + return make_real_if(c, t, e); + }); + }; + + function abort_else(c, t, e) { + var ret = [ [ "if", negate(c), e ] ]; + if (t[0] == "block") { + if (t[1]) ret = ret.concat(t[1]); + } else { + ret.push(t); + } + return walk([ "block", ret ]); + }; + + function make_real_if(c, t, e) { + c = walk(c); + t = walk(t); + e = walk(e); + + if (empty(e) && empty(t)) + return [ "stat", c ]; + + if (empty(t)) { + c = negate(c); + t = e; + e = null; + } else if (empty(e)) { + e = null; + } else { + // if we have both else and then, maybe it makes sense to switch them? + (function(){ + var a = gen_code(c); + var n = negate(c); + var b = gen_code(n); + if (b.length < a.length) { + var tmp = t; + t = e; + e = tmp; + c = n; + } + })(); + } + var ret = [ "if", c, t, e ]; + if (t[0] == "if" && empty(t[3]) && empty(e)) { + ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ])); + } + else if (t[0] == "stat") { + if (e) { + if (e[0] == "stat") + ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]); + else if (aborts(e)) + ret = abort_else(c, t, e); + } + else { + ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]); + } + } + else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw") && t[1] && e[1]) { + ret = best_of(ret, [ t[0], make_conditional(c, t[1], e[1] ) ]); + } + else if (e && aborts(t)) { + ret = [ [ "if", c, t ] ]; + if (e[0] == "block") { + if (e[1]) ret = ret.concat(e[1]); + } + else { + ret.push(e); + } + ret = walk([ "block", ret ]); + } + else if (t && aborts(e)) { + ret = abort_else(c, t, e); + } + return ret; + }; + + function _do_while(cond, body) { + return when_constant(cond, function(cond, val){ + if (!val) { + warn_unreachable(body); + return [ "block" ]; + } else { + return [ "for", null, null, null, walk(body) ]; + } + }); + }; + + return w.with_walkers({ + "sub": function(expr, subscript) { + if (subscript[0] == "string") { + var name = subscript[1]; + if (is_identifier(name)) + return [ "dot", walk(expr), name ]; + else if (/^[1-9][0-9]*$/.test(name) || name === "0") + return [ "sub", walk(expr), [ "num", parseInt(name, 10) ] ]; + } + }, + "if": make_if, + "toplevel": function(body) { + return [ "toplevel", tighten(body) ]; + }, + "switch": function(expr, body) { + var last = body.length - 1; + return [ "switch", walk(expr), MAP(body, function(branch, i){ + var block = tighten(branch[1]); + if (i == last && block.length > 0) { + var node = block[block.length - 1]; + if (node[0] == "break" && !node[1]) + block.pop(); + } + return [ branch[0] ? walk(branch[0]) : null, block ]; + }) ]; + }, + "function": _lambda, + "defun": _lambda, + "block": function(body) { + if (body) return rmblock([ "block", tighten(body) ]); + }, + "binary": function(op, left, right) { + return when_constant([ "binary", op, walk(left), walk(right) ], function yes(c){ + return best_of(walk(c), this); + }, function no() { + return function(){ + if(op != "==" && op != "!=") return; + var l = walk(left), r = walk(right); + if(l && l[0] == "unary-prefix" && l[1] == "!" && l[2][0] == "num") + left = ['num', +!l[2][1]]; + else if (r && r[0] == "unary-prefix" && r[1] == "!" && r[2][0] == "num") + right = ['num', +!r[2][1]]; + return ["binary", op, left, right]; + }() || this; + }); + }, + "conditional": function(c, t, e) { + return make_conditional(walk(c), walk(t), walk(e)); + }, + "try": function(t, c, f) { + return [ + "try", + tighten(t), + c != null ? [ c[0], tighten(c[1]) ] : null, + f != null ? tighten(f) : null + ]; + }, + "unary-prefix": function(op, expr) { + expr = walk(expr); + var ret = [ "unary-prefix", op, expr ]; + if (op == "!") + ret = best_of(ret, negate(expr)); + return when_constant(ret, function(ast, val){ + return walk(ast); // it's either true or false, so minifies to !0 or !1 + }, function() { return ret }); + }, + "name": function(name) { + switch (name) { + case "true": return [ "unary-prefix", "!", [ "num", 0 ]]; + case "false": return [ "unary-prefix", "!", [ "num", 1 ]]; + } + }, + "while": _do_while, + "assign": function(op, lvalue, rvalue) { + lvalue = walk(lvalue); + rvalue = walk(rvalue); + var okOps = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ]; + if (op === true && lvalue[0] === "name" && rvalue[0] === "binary" && + ~okOps.indexOf(rvalue[1]) && rvalue[2][0] === "name" && + rvalue[2][1] === lvalue[1]) { + return [ this[0], rvalue[1], lvalue, rvalue[3] ] + } + return [ this[0], op, lvalue, rvalue ]; + }, + "call": function(expr, args) { + expr = walk(expr); + if (options.unsafe && expr[0] == "dot" && expr[1][0] == "string" && expr[2] == "toString") { + return expr[1]; + } + return [ this[0], expr, MAP(args, walk) ]; + }, + "num": function (num) { + if (!isFinite(num)) + return [ "binary", "/", num === 1 / 0 + ? [ "num", 1 ] : num === -1 / 0 + ? [ "unary-prefix", "-", [ "num", 1 ] ] + : [ "num", 0 ], [ "num", 0 ] ]; + + return [ this[0], num ]; + } + }, function() { + return walk(prepare_ifs(walk(prepare_ifs(ast)))); + }); +}; + +function squeeze_2(ast, options) { + var w = ast_walker(), walk = w.walk, scope; + function with_scope(s, cont) { + var save = scope, ret; + scope = s; + ret = cont(); + scope = save; + return ret; + }; + function lambda(name, args, body) { + return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ]; + }; + return w.with_walkers({ + "directive": function(dir) { + if (scope.active_directive(dir)) + return [ "block" ]; + scope.directives.push(dir); + }, + "toplevel": function(body) { + return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ]; + }, + "function": lambda, + "defun": lambda + }, function(){ + return walk(ast_add_scope(ast)); + }); +}; + +/* -----[ re-generate code from the AST ]----- */ + +var DOT_CALL_NO_PARENS = jsp.array_to_hash([ + "name", + "array", + "object", + "string", + "dot", + "sub", + "call", + "regexp", + "defun" +]); + +function make_string(str, ascii_only) { + var dq = 0, sq = 0; + str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){ + switch (s) { + case "\\": return "\\\\"; + case "\b": return "\\b"; + case "\f": return "\\f"; + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\u2028": return "\\u2028"; + case "\u2029": return "\\u2029"; + case '"': ++dq; return '"'; + case "'": ++sq; return "'"; + case "\0": return "\\0"; + } + return s; + }); + if (ascii_only) str = to_ascii(str); + if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; + else return '"' + str.replace(/\x22/g, '\\"') + '"'; +}; + +function to_ascii(str) { + return str.replace(/[\u0080-\uffff]/g, function(ch) { + var code = ch.charCodeAt(0).toString(16); + while (code.length < 4) code = "0" + code; + return "\\u" + code; + }); +}; + +var SPLICE_NEEDS_BRACKETS = jsp.array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]); + +function gen_code(ast, options) { + options = defaults(options, { + indent_start : 0, + indent_level : 4, + quote_keys : false, + space_colon : false, + beautify : false, + ascii_only : false, + inline_script: false + }); + var beautify = !!options.beautify; + var indentation = 0, + newline = beautify ? "\n" : "", + space = beautify ? " " : ""; + + function encode_string(str) { + var ret = make_string(str, options.ascii_only); + if (options.inline_script) + ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); + return ret; + }; + + function make_name(name) { + name = name.toString(); + if (options.ascii_only) + name = to_ascii(name); + return name; + }; + + function indent(line) { + if (line == null) + line = ""; + if (beautify) + line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line; + return line; + }; + + function with_indent(cont, incr) { + if (incr == null) incr = 1; + indentation += incr; + try { return cont.apply(null, slice(arguments, 1)); } + finally { indentation -= incr; } + }; + + function last_char(str) { + str = str.toString(); + return str.charAt(str.length - 1); + }; + + function first_char(str) { + return str.toString().charAt(0); + }; + + function add_spaces(a) { + if (beautify) + return a.join(" "); + var b = []; + for (var i = 0; i < a.length; ++i) { + var next = a[i + 1]; + b.push(a[i]); + if (next && + ((is_identifier_char(last_char(a[i])) && (is_identifier_char(first_char(next)) + || first_char(next) == "\\")) || + (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString()) || + last_char(a[i]) == "/" && first_char(next) == "/"))) { + b.push(" "); + } + } + return b.join(""); + }; + + function add_commas(a) { + return a.join("," + space); + }; + + function parenthesize(expr) { + var gen = make(expr); + for (var i = 1; i < arguments.length; ++i) { + var el = arguments[i]; + if ((el instanceof Function && el(expr)) || expr[0] == el) + return "(" + gen + ")"; + } + return gen; + }; + + function best_of(a) { + if (a.length == 1) { + return a[0]; + } + if (a.length == 2) { + var b = a[1]; + a = a[0]; + return a.length <= b.length ? a : b; + } + return best_of([ a[0], best_of(a.slice(1)) ]); + }; + + function needs_parens(expr) { + if (expr[0] == "function" || expr[0] == "object") { + // dot/call on a literal function requires the + // function literal itself to be parenthesized + // only if it's the first "thing" in a + // statement. This means that the parent is + // "stat", but it could also be a "seq" and + // we're the first in this "seq" and the + // parent is "stat", and so on. Messy stuff, + // but it worths the trouble. + var a = slice(w.stack()), self = a.pop(), p = a.pop(); + while (p) { + if (p[0] == "stat") return true; + if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) || + ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) { + self = p; + p = a.pop(); + } else { + return false; + } + } + } + return !HOP(DOT_CALL_NO_PARENS, expr[0]); + }; + + function make_num(num) { + var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m; + if (Math.floor(num) === num) { + if (num >= 0) { + a.push("0x" + num.toString(16).toLowerCase(), // probably pointless + "0" + num.toString(8)); // same. + } else { + a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless + "-0" + (-num).toString(8)); // same. + } + if ((m = /^(.*?)(0+)$/.exec(num))) { + a.push(m[1] + "e" + m[2].length); + } + } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) { + a.push(m[2] + "e-" + (m[1].length + m[2].length), + str.substr(str.indexOf("."))); + } + return best_of(a); + }; + + var w = ast_walker(); + var make = w.walk; + return w.with_walkers({ + "string": encode_string, + "num": make_num, + "name": make_name, + "debugger": function(){ return "debugger;" }, + "toplevel": function(statements) { + return make_block_statements(statements) + .join(newline + newline); + }, + "splice": function(statements) { + var parent = w.parent(); + if (HOP(SPLICE_NEEDS_BRACKETS, parent)) { + // we need block brackets in this case + return make_block.apply(this, arguments); + } else { + return MAP(make_block_statements(statements, true), + function(line, i) { + // the first line is already indented + return i > 0 ? indent(line) : line; + }).join(newline); + } + }, + "block": make_block, + "var": function(defs) { + return "var " + add_commas(MAP(defs, make_1vardef)) + ";"; + }, + "const": function(defs) { + return "const " + add_commas(MAP(defs, make_1vardef)) + ";"; + }, + "try": function(tr, ca, fi) { + var out = [ "try", make_block(tr) ]; + if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1])); + if (fi) out.push("finally", make_block(fi)); + return add_spaces(out); + }, + "throw": function(expr) { + return add_spaces([ "throw", make(expr) ]) + ";"; + }, + "new": function(ctor, args) { + args = args.length > 0 ? "(" + add_commas(MAP(args, function(expr){ + return parenthesize(expr, "seq"); + })) + ")" : ""; + return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){ + var w = ast_walker(), has_call = {}; + try { + w.with_walkers({ + "call": function() { throw has_call }, + "function": function() { return this } + }, function(){ + w.walk(expr); + }); + } catch(ex) { + if (ex === has_call) + return true; + throw ex; + } + }) + args ]); + }, + "switch": function(expr, body) { + return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]); + }, + "break": function(label) { + var out = "break"; + if (label != null) + out += " " + make_name(label); + return out + ";"; + }, + "continue": function(label) { + var out = "continue"; + if (label != null) + out += " " + make_name(label); + return out + ";"; + }, + "conditional": function(co, th, el) { + return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?", + parenthesize(th, "seq"), ":", + parenthesize(el, "seq") ]); + }, + "assign": function(op, lvalue, rvalue) { + if (op && op !== true) op += "="; + else op = "="; + return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]); + }, + "dot": function(expr) { + var out = make(expr), i = 1; + if (expr[0] == "num") { + if (!/[a-f.]/i.test(out)) + out += "."; + } else if (expr[0] != "function" && needs_parens(expr)) + out = "(" + out + ")"; + while (i < arguments.length) + out += "." + make_name(arguments[i++]); + return out; + }, + "call": function(func, args) { + var f = make(func); + if (f.charAt(0) != "(" && needs_parens(func)) + f = "(" + f + ")"; + return f + "(" + add_commas(MAP(args, function(expr){ + return parenthesize(expr, "seq"); + })) + ")"; + }, + "function": make_function, + "defun": make_function, + "if": function(co, th, el) { + var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ]; + if (el) { + out.push("else", make(el)); + } + return add_spaces(out); + }, + "for": function(init, cond, step, block) { + var out = [ "for" ]; + init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space); + cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space); + step = (step != null ? make(step) : "").replace(/;*\s*$/, ""); + var args = init + cond + step; + if (args == "; ; ") args = ";;"; + out.push("(" + args + ")", make(block)); + return add_spaces(out); + }, + "for-in": function(vvar, key, hash, block) { + return add_spaces([ "for", "(" + + (vvar ? make(vvar).replace(/;+$/, "") : make(key)), + "in", + make(hash) + ")", make(block) ]); + }, + "while": function(condition, block) { + return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]); + }, + "do": function(condition, block) { + return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";"; + }, + "return": function(expr) { + var out = [ "return" ]; + if (expr != null) out.push(make(expr)); + return add_spaces(out) + ";"; + }, + "binary": function(operator, lvalue, rvalue) { + var left = make(lvalue), right = make(rvalue); + // XXX: I'm pretty sure other cases will bite here. + // we need to be smarter. + // adding parens all the time is the safest bet. + if (member(lvalue[0], [ "assign", "conditional", "seq" ]) || + lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]] || + lvalue[0] == "function" && needs_parens(this)) { + left = "(" + left + ")"; + } + if (member(rvalue[0], [ "assign", "conditional", "seq" ]) || + rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] && + !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) { + right = "(" + right + ")"; + } + else if (!beautify && options.inline_script && (operator == "<" || operator == "<<") + && rvalue[0] == "regexp" && /^script/i.test(rvalue[1])) { + right = " " + right; + } + return add_spaces([ left, operator, right ]); + }, + "unary-prefix": function(operator, expr) { + var val = make(expr); + if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) + val = "(" + val + ")"; + return operator + (jsp.is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val; + }, + "unary-postfix": function(operator, expr) { + var val = make(expr); + if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) + val = "(" + val + ")"; + return val + operator; + }, + "sub": function(expr, subscript) { + var hash = make(expr); + if (needs_parens(expr)) + hash = "(" + hash + ")"; + return hash + "[" + make(subscript) + "]"; + }, + "object": function(props) { + var obj_needs_parens = needs_parens(this); + if (props.length == 0) + return obj_needs_parens ? "({})" : "{}"; + var out = "{" + newline + with_indent(function(){ + return MAP(props, function(p){ + if (p.length == 3) { + // getter/setter. The name is in p[0], the arg.list in p[1][2], the + // body in p[1][3] and type ("get" / "set") in p[2]. + return indent(make_function(p[0], p[1][2], p[1][3], p[2], true)); + } + var key = p[0], val = parenthesize(p[1], "seq"); + if (options.quote_keys) { + key = encode_string(key); + } else if ((typeof key == "number" || !beautify && +key + "" == key) + && parseFloat(key) >= 0) { + key = make_num(+key); + } else if (!is_identifier(key)) { + key = encode_string(key); + } + return indent(add_spaces(beautify && options.space_colon + ? [ key, ":", val ] + : [ key + ":", val ])); + }).join("," + newline); + }) + newline + indent("}"); + return obj_needs_parens ? "(" + out + ")" : out; + }, + "regexp": function(rx, mods) { + if (options.ascii_only) rx = to_ascii(rx); + return "/" + rx + "/" + mods; + }, + "array": function(elements) { + if (elements.length == 0) return "[]"; + return add_spaces([ "[", add_commas(MAP(elements, function(el, i){ + if (!beautify && el[0] == "atom" && el[1] == "undefined") return i === elements.length - 1 ? "," : ""; + return parenthesize(el, "seq"); + })), "]" ]); + }, + "stat": function(stmt) { + return stmt != null + ? make(stmt).replace(/;*\s*$/, ";") + : ";"; + }, + "seq": function() { + return add_commas(MAP(slice(arguments), make)); + }, + "label": function(name, block) { + return add_spaces([ make_name(name), ":", make(block) ]); + }, + "with": function(expr, block) { + return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]); + }, + "atom": function(name) { + return make_name(name); + }, + "directive": function(dir) { + return make_string(dir) + ";"; + } + }, function(){ return make(ast) }); + + // The squeezer replaces "block"-s that contain only a single + // statement with the statement itself; technically, the AST + // is correct, but this can create problems when we output an + // IF having an ELSE clause where the THEN clause ends in an + // IF *without* an ELSE block (then the outer ELSE would refer + // to the inner IF). This function checks for this case and + // adds the block brackets if needed. + function make_then(th) { + if (th == null) return ";"; + if (th[0] == "do") { + // https://github.com/mishoo/UglifyJS/issues/#issue/57 + // IE croaks with "syntax error" on code like this: + // if (foo) do ... while(cond); else ... + // we need block brackets around do/while + return make_block([ th ]); + } + var b = th; + while (true) { + var type = b[0]; + if (type == "if") { + if (!b[3]) + // no else, we must add the block + return make([ "block", [ th ]]); + b = b[3]; + } + else if (type == "while" || type == "do") b = b[2]; + else if (type == "for" || type == "for-in") b = b[4]; + else break; + } + return make(th); + }; + + function make_function(name, args, body, keyword, no_parens) { + var out = keyword || "function"; + if (name) { + out += " " + make_name(name); + } + out += "(" + add_commas(MAP(args, make_name)) + ")"; + out = add_spaces([ out, make_block(body) ]); + return (!no_parens && needs_parens(this)) ? "(" + out + ")" : out; + }; + + function must_has_semicolon(node) { + switch (node[0]) { + case "with": + case "while": + return empty(node[2]) || must_has_semicolon(node[2]); + case "for": + case "for-in": + return empty(node[4]) || must_has_semicolon(node[4]); + case "if": + if (empty(node[2]) && !node[3]) return true; // `if' with empty `then' and no `else' + if (node[3]) { + if (empty(node[3])) return true; // `else' present but empty + return must_has_semicolon(node[3]); // dive into the `else' branch + } + return must_has_semicolon(node[2]); // dive into the `then' branch + case "directive": + return true; + } + }; + + function make_block_statements(statements, noindent) { + for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) { + var stat = statements[i]; + var code = make(stat); + if (code != ";") { + if (!beautify && i == last && !must_has_semicolon(stat)) { + code = code.replace(/;+\s*$/, ""); + } + a.push(code); + } + } + return noindent ? a : MAP(a, indent); + }; + + function make_switch_block(body) { + var n = body.length; + if (n == 0) return "{}"; + return "{" + newline + MAP(body, function(branch, i){ + var has_body = branch[1].length > 0, code = with_indent(function(){ + return indent(branch[0] + ? add_spaces([ "case", make(branch[0]) + ":" ]) + : "default:"); + }, 0.5) + (has_body ? newline + with_indent(function(){ + return make_block_statements(branch[1]).join(newline); + }) : ""); + if (!beautify && has_body && i < n - 1) + code += ";"; + return code; + }).join(newline) + newline + indent("}"); + }; + + function make_block(statements) { + if (!statements) return ";"; + if (statements.length == 0) return "{}"; + return "{" + newline + with_indent(function(){ + return make_block_statements(statements).join(newline); + }) + newline + indent("}"); + }; + + function make_1vardef(def) { + var name = def[0], val = def[1]; + if (val != null) + name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]); + return name; + }; + +}; + +function split_lines(code, max_line_length) { + var splits = [ 0 ]; + jsp.parse(function(){ + var next_token = jsp.tokenizer(code); + var last_split = 0; + var prev_token; + function current_length(tok) { + return tok.pos - last_split; + }; + function split_here(tok) { + last_split = tok.pos; + splits.push(last_split); + }; + function custom(){ + var tok = next_token.apply(this, arguments); + out: { + if (prev_token) { + if (prev_token.type == "keyword") break out; + } + if (current_length(tok) > max_line_length) { + switch (tok.type) { + case "keyword": + case "atom": + case "name": + case "punc": + split_here(tok); + break out; + } + } + } + prev_token = tok; + return tok; + }; + custom.context = function() { + return next_token.context.apply(this, arguments); + }; + return custom; + }()); + return splits.map(function(pos, i){ + return code.substring(pos, splits[i + 1] || code.length); + }).join("\n"); +}; + +/* -----[ Utilities ]----- */ + +function repeat_string(str, i) { + if (i <= 0) return ""; + if (i == 1) return str; + var d = repeat_string(str, i >> 1); + d += d; + if (i & 1) d += str; + return d; +}; + +function defaults(args, defs) { + var ret = {}; + if (args === true) + args = {}; + for (var i in defs) if (HOP(defs, i)) { + ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; + } + return ret; +}; + +function is_identifier(name) { + return /^[a-z_$][a-z0-9_$]*$/i.test(name) + && name != "this" + && !HOP(jsp.KEYWORDS_ATOM, name) + && !HOP(jsp.RESERVED_WORDS, name) + && !HOP(jsp.KEYWORDS, name); +}; + +function HOP(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +}; + +// some utilities + +var MAP; + +(function(){ + MAP = function(a, f, o) { + var ret = [], top = [], i; + function doit() { + var val = f.call(o, a[i], i); + if (val instanceof AtTop) { + val = val.v; + if (val instanceof Splice) { + top.push.apply(top, val.v); + } else { + top.push(val); + } + } + else if (val != skip) { + if (val instanceof Splice) { + ret.push.apply(ret, val.v); + } else { + ret.push(val); + } + } + }; + if (a instanceof Array) for (i = 0; i < a.length; ++i) doit(); + else for (i in a) if (HOP(a, i)) doit(); + return top.concat(ret); + }; + MAP.at_top = function(val) { return new AtTop(val) }; + MAP.splice = function(val) { return new Splice(val) }; + var skip = MAP.skip = {}; + function AtTop(val) { this.v = val }; + function Splice(val) { this.v = val }; +})(); + +/* -----[ Exports ]----- */ + +exports.ast_walker = ast_walker; +exports.ast_mangle = ast_mangle; +exports.ast_squeeze = ast_squeeze; +exports.ast_lift_variables = ast_lift_variables; +exports.gen_code = gen_code; +exports.ast_add_scope = ast_add_scope; +exports.set_logger = function(logger) { warn = logger }; +exports.make_string = make_string; +exports.split_lines = split_lines; +exports.MAP = MAP; + +// keep this last! +exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more; + +// Local variables: +// js-indent-level: 4 +// End: +}); +define('uglifyjs/index', ["require", "exports", "module", "./parse-js", "./process", "./consolidator"], function(require, exports, module) { +//convienence function(src, [options]); +function uglify(orig_code, options){ + options || (options = {}); + var jsp = uglify.parser; + var pro = uglify.uglify; + + var ast = jsp.parse(orig_code, options.strict_semicolons); // parse code and get the initial AST + ast = pro.ast_mangle(ast, options.mangle_options); // get a new AST with mangled names + ast = pro.ast_squeeze(ast, options.squeeze_options); // get an AST with compression optimizations + var final_code = pro.gen_code(ast, options.gen_options); // compressed code here + return final_code; +}; + +uglify.parser = require("./parse-js"); +uglify.uglify = require("./process"); +uglify.consolidator = require("./consolidator"); + +module.exports = uglify +});/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +define('source-map/array-set', function (require, exports, module) { + + var util = require('./util'); + + /** + * A data structure which is a combination of an array and a set. Adding a new + * member is O(1), testing for membership is O(1), and finding the index of an + * element is O(1). Removing elements from the set is not supported. Only + * strings are supported for membership. + */ + function ArraySet() { + this._array = []; + this._set = {}; + } + + /** + * Static method for creating ArraySet instances from an existing array. + */ + ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { + var set = new ArraySet(); + for (var i = 0, len = aArray.length; i < len; i++) { + set.add(aArray[i], aAllowDuplicates); + } + return set; + }; + + /** + * Add the given string to this set. + * + * @param String aStr + */ + ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { + var isDuplicate = this.has(aStr); + var idx = this._array.length; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { + this._set[util.toSetString(aStr)] = idx; + } + }; + + /** + * Is the given string a member of this set? + * + * @param String aStr + */ + ArraySet.prototype.has = function ArraySet_has(aStr) { + return Object.prototype.hasOwnProperty.call(this._set, + util.toSetString(aStr)); + }; + + /** + * What is the index of the given string in the array? + * + * @param String aStr + */ + ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { + if (this.has(aStr)) { + return this._set[util.toSetString(aStr)]; + } + throw new Error('"' + aStr + '" is not in the set.'); + }; + + /** + * What is the element at the given index? + * + * @param Number aIdx + */ + ArraySet.prototype.at = function ArraySet_at(aIdx) { + if (aIdx >= 0 && aIdx < this._array.length) { + return this._array[aIdx]; + } + throw new Error('No element indexed by ' + aIdx); + }; + + /** + * Returns the array representation of this set (which has the proper indices + * indicated by indexOf). Note that this is a copy of the internal array used + * for storing the members so that no one can mess with internal state. + */ + ArraySet.prototype.toArray = function ArraySet_toArray() { + return this._array.slice(); + }; + + exports.ArraySet = ArraySet; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + * + * Based on the Base 64 VLQ implementation in Closure Compiler: + * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java + * + * Copyright 2011 The Closure Compiler Authors. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +define('source-map/base64-vlq', function (require, exports, module) { + + var base64 = require('./base64'); + + // A single base 64 digit can contain 6 bits of data. For the base 64 variable + // length quantities we use in the source map spec, the first bit is the sign, + // the next four bits are the actual value, and the 6th bit is the + // continuation bit. The continuation bit tells us whether there are more + // digits in this value following this digit. + // + // Continuation + // | Sign + // | | + // V V + // 101011 + + var VLQ_BASE_SHIFT = 5; + + // binary: 100000 + var VLQ_BASE = 1 << VLQ_BASE_SHIFT; + + // binary: 011111 + var VLQ_BASE_MASK = VLQ_BASE - 1; + + // binary: 100000 + var VLQ_CONTINUATION_BIT = VLQ_BASE; + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + */ + function toVLQSigned(aValue) { + return aValue < 0 + ? ((-aValue) << 1) + 1 + : (aValue << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + */ + function fromVLQSigned(aValue) { + var isNegative = (aValue & 1) === 1; + var shifted = aValue >> 1; + return isNegative + ? -shifted + : shifted; + } + + /** + * Returns the base 64 VLQ encoded value. + */ + exports.encode = function base64VLQ_encode(aValue) { + var encoded = ""; + var digit; + + var vlq = toVLQSigned(aValue); + + do { + digit = vlq & VLQ_BASE_MASK; + vlq >>>= VLQ_BASE_SHIFT; + if (vlq > 0) { + // There are still more digits in this value, so we must make sure the + // continuation bit is marked. + digit |= VLQ_CONTINUATION_BIT; + } + encoded += base64.encode(digit); + } while (vlq > 0); + + return encoded; + }; + + /** + * Decodes the next base 64 VLQ value from the given string and returns the + * value and the rest of the string. + */ + exports.decode = function base64VLQ_decode(aStr) { + var i = 0; + var strLen = aStr.length; + var result = 0; + var shift = 0; + var continuation, digit; + + do { + if (i >= strLen) { + throw new Error("Expected more digits in base 64 VLQ value."); + } + digit = base64.decode(aStr.charAt(i++)); + continuation = !!(digit & VLQ_CONTINUATION_BIT); + digit &= VLQ_BASE_MASK; + result = result + (digit << shift); + shift += VLQ_BASE_SHIFT; + } while (continuation); + + return { + value: fromVLQSigned(result), + rest: aStr.slice(i) + }; + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +define('source-map/base64', function (require, exports, module) { + + var charToIntMap = {}; + var intToCharMap = {}; + + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + .split('') + .forEach(function (ch, index) { + charToIntMap[ch] = index; + intToCharMap[index] = ch; + }); + + /** + * Encode an integer in the range of 0 to 63 to a single base 64 digit. + */ + exports.encode = function base64_encode(aNumber) { + if (aNumber in intToCharMap) { + return intToCharMap[aNumber]; + } + throw new TypeError("Must be between 0 and 63: " + aNumber); + }; + + /** + * Decode a single base 64 digit to an integer. + */ + exports.decode = function base64_decode(aChar) { + if (aChar in charToIntMap) { + return charToIntMap[aChar]; + } + throw new TypeError("Not a valid base 64 digit: " + aChar); + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +define('source-map/binary-search', function (require, exports, module) { + + /** + * Recursive implementation of binary search. + * + * @param aLow Indices here and lower do not contain the needle. + * @param aHigh Indices here and higher do not contain the needle. + * @param aNeedle The element being searched for. + * @param aHaystack The non-empty array being searched. + * @param aCompare Function which takes two elements and returns -1, 0, or 1. + */ + function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { + // This function terminates when one of the following is true: + // + // 1. We find the exact element we are looking for. + // + // 2. We did not find the exact element, but we can return the next + // closest element that is less than that element. + // + // 3. We did not find the exact element, and there is no next-closest + // element which is less than the one we are searching for, so we + // return null. + var mid = Math.floor((aHigh - aLow) / 2) + aLow; + var cmp = aCompare(aNeedle, aHaystack[mid], true); + if (cmp === 0) { + // Found the element we are looking for. + return aHaystack[mid]; + } + else if (cmp > 0) { + // aHaystack[mid] is greater than our needle. + if (aHigh - mid > 1) { + // The element is in the upper half. + return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); + } + // We did not find an exact match, return the next closest one + // (termination case 2). + return aHaystack[mid]; + } + else { + // aHaystack[mid] is less than our needle. + if (mid - aLow > 1) { + // The element is in the lower half. + return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); + } + // The exact needle element was not found in this haystack. Determine if + // we are in termination case (2) or (3) and return the appropriate thing. + return aLow < 0 + ? null + : aHaystack[aLow]; + } + } + + /** + * This is an implementation of binary search which will always try and return + * the next lowest value checked if there is no exact hit. This is because + * mappings between original and generated line/col pairs are single points, + * and there is an implicit region between each of them, so a miss just means + * that you aren't on the very start of a region. + * + * @param aNeedle The element you are looking for. + * @param aHaystack The array that is being searched. + * @param aCompare A function which takes the needle and an element in the + * array and returns -1, 0, or 1 depending on whether the needle is less + * than, equal to, or greater than the element, respectively. + */ + exports.search = function search(aNeedle, aHaystack, aCompare) { + return aHaystack.length > 0 + ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) + : null; + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +define('source-map/source-map-consumer', function (require, exports, module) { + + var util = require('./util'); + var binarySearch = require('./binary-search'); + var ArraySet = require('./array-set').ArraySet; + var base64VLQ = require('./base64-vlq'); + + /** + * A SourceMapConsumer instance represents a parsed source map which we can + * query for information about the original file positions by giving it a file + * position in the generated source. + * + * The only parameter is the raw source map (either as a JSON string, or + * already parsed to an object). According to the spec, source maps have the + * following attributes: + * + * - version: Which version of the source map spec this map is following. + * - sources: An array of URLs to the original source files. + * - names: An array of identifiers which can be referrenced by individual mappings. + * - sourceRoot: Optional. The URL root from which all sources are relative. + * - sourcesContent: Optional. An array of contents of the original source files. + * - mappings: A string of base64 VLQs which contain the actual mappings. + * - file: The generated file this source map is associated with. + * + * Here is an example source map, taken from the source map spec[0]: + * + * { + * version : 3, + * file: "out.js", + * sourceRoot : "", + * sources: ["foo.js", "bar.js"], + * names: ["src", "maps", "are", "fun"], + * mappings: "AA,AB;;ABCDE;" + * } + * + * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# + */ + function SourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } + + var version = util.getArg(sourceMap, 'version'); + var sources = util.getArg(sourceMap, 'sources'); + var names = util.getArg(sourceMap, 'names'); + var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); + var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); + var mappings = util.getArg(sourceMap, 'mappings'); + var file = util.getArg(sourceMap, 'file', null); + + if (version !== this._version) { + throw new Error('Unsupported version: ' + version); + } + + // Pass `true` below to allow duplicate names and sources. While source maps + // are intended to be compressed and deduplicated, the TypeScript compiler + // sometimes generates source maps with duplicates in them. See Github issue + // #72 and bugzil.la/889492. + this._names = ArraySet.fromArray(names, true); + this._sources = ArraySet.fromArray(sources, true); + this.sourceRoot = sourceRoot; + this.sourcesContent = sourcesContent; + this.file = file; + + // `this._generatedMappings` and `this._originalMappings` hold the parsed + // mapping coordinates from the source map's "mappings" attribute. Each + // object in the array is of the form + // + // { + // generatedLine: The line number in the generated code, + // generatedColumn: The column number in the generated code, + // source: The path to the original source file that generated this + // chunk of code, + // originalLine: The line number in the original source that + // corresponds to this chunk of generated code, + // originalColumn: The column number in the original source that + // corresponds to this chunk of generated code, + // name: The name of the original symbol which generated this chunk of + // code. + // } + // + // All properties except for `generatedLine` and `generatedColumn` can be + // `null`. + // + // `this._generatedMappings` is ordered by the generated positions. + // + // `this._originalMappings` is ordered by the original positions. + this._generatedMappings = []; + this._originalMappings = []; + this._parseMappings(mappings, sourceRoot); + } + + /** + * Create a SourceMapConsumer from a SourceMapGenerator. + * + * @param SourceMapGenerator aSourceMap + * The source map that will be consumed. + * @returns SourceMapConsumer + */ + SourceMapConsumer.fromSourceMap = + function SourceMapConsumer_fromSourceMap(aSourceMap) { + var smc = Object.create(SourceMapConsumer.prototype); + + smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); + smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); + smc.sourceRoot = aSourceMap._sourceRoot; + smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), + smc.sourceRoot); + smc.file = aSourceMap._file; + + smc._generatedMappings = aSourceMap._mappings.slice() + .sort(util.compareByGeneratedPositions); + smc._originalMappings = aSourceMap._mappings.slice() + .sort(util.compareByOriginalPositions); + + return smc; + }; + + /** + * The version of the source mapping spec that we are consuming. + */ + SourceMapConsumer.prototype._version = 3; + + /** + * The list of original sources. + */ + Object.defineProperty(SourceMapConsumer.prototype, 'sources', { + get: function () { + return this._sources.toArray().map(function (s) { + return this.sourceRoot ? util.join(this.sourceRoot, s) : s; + }, this); + } + }); + + /** + * Parse the mappings in a string in to a data structure which we can easily + * query (an ordered list in this._generatedMappings). + */ + SourceMapConsumer.prototype._parseMappings = + function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { + var generatedLine = 1; + var previousGeneratedColumn = 0; + var previousOriginalLine = 0; + var previousOriginalColumn = 0; + var previousSource = 0; + var previousName = 0; + var mappingSeparator = /^[,;]/; + var str = aStr; + var mapping; + var temp; + + while (str.length > 0) { + if (str.charAt(0) === ';') { + generatedLine++; + str = str.slice(1); + previousGeneratedColumn = 0; + } + else if (str.charAt(0) === ',') { + str = str.slice(1); + } + else { + mapping = {}; + mapping.generatedLine = generatedLine; + + // Generated column. + temp = base64VLQ.decode(str); + mapping.generatedColumn = previousGeneratedColumn + temp.value; + previousGeneratedColumn = mapping.generatedColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original source. + temp = base64VLQ.decode(str); + mapping.source = this._sources.at(previousSource + temp.value); + previousSource += temp.value; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source, but no line and column'); + } + + // Original line. + temp = base64VLQ.decode(str); + mapping.originalLine = previousOriginalLine + temp.value; + previousOriginalLine = mapping.originalLine; + // Lines are stored 0-based + mapping.originalLine += 1; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source and line, but no column'); + } + + // Original column. + temp = base64VLQ.decode(str); + mapping.originalColumn = previousOriginalColumn + temp.value; + previousOriginalColumn = mapping.originalColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original name. + temp = base64VLQ.decode(str); + mapping.name = this._names.at(previousName + temp.value); + previousName += temp.value; + str = temp.rest; + } + } + + this._generatedMappings.push(mapping); + if (typeof mapping.originalLine === 'number') { + this._originalMappings.push(mapping); + } + } + } + + this._originalMappings.sort(util.compareByOriginalPositions); + }; + + /** + * Find the mapping that best matches the hypothetical "needle" mapping that + * we are searching for in the given "haystack" of mappings. + */ + SourceMapConsumer.prototype._findMapping = + function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, + aColumnName, aComparator) { + // To return the position we are searching for, we must first find the + // mapping for the given position and then return the opposite position it + // points to. Because the mappings are sorted, we can use binary search to + // find the best mapping. + + if (aNeedle[aLineName] <= 0) { + throw new TypeError('Line must be greater than or equal to 1, got ' + + aNeedle[aLineName]); + } + if (aNeedle[aColumnName] < 0) { + throw new TypeError('Column must be greater than or equal to 0, got ' + + aNeedle[aColumnName]); + } + + return binarySearch.search(aNeedle, aMappings, aComparator); + }; + + /** + * Returns the original source, line, and column information for the generated + * source's line and column positions provided. The only argument is an object + * with the following properties: + * + * - line: The line number in the generated source. + * - column: The column number in the generated source. + * + * and an object is returned with the following properties: + * + * - source: The original source file, or null. + * - line: The line number in the original source, or null. + * - column: The column number in the original source, or null. + * - name: The original identifier, or null. + */ + SourceMapConsumer.prototype.originalPositionFor = + function SourceMapConsumer_originalPositionFor(aArgs) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; + + var mapping = this._findMapping(needle, + this._generatedMappings, + "generatedLine", + "generatedColumn", + util.compareByGeneratedPositions); + + if (mapping) { + var source = util.getArg(mapping, 'source', null); + if (source && this.sourceRoot) { + source = util.join(this.sourceRoot, source); + } + return { + source: source, + line: util.getArg(mapping, 'originalLine', null), + column: util.getArg(mapping, 'originalColumn', null), + name: util.getArg(mapping, 'name', null) + }; + } + + return { + source: null, + line: null, + column: null, + name: null + }; + }; + + /** + * Returns the original source content. The only argument is the url of the + * original source file. Returns null if no original source content is + * availible. + */ + SourceMapConsumer.prototype.sourceContentFor = + function SourceMapConsumer_sourceContentFor(aSource) { + if (!this.sourcesContent) { + return null; + } + + if (this.sourceRoot) { + aSource = util.relative(this.sourceRoot, aSource); + } + + if (this._sources.has(aSource)) { + return this.sourcesContent[this._sources.indexOf(aSource)]; + } + + var url; + if (this.sourceRoot + && (url = util.urlParse(this.sourceRoot))) { + // XXX: file:// URIs and absolute paths lead to unexpected behavior for + // many users. We can help them out when they expect file:// URIs to + // behave like it would if they were running a local HTTP server. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. + var fileUriAbsPath = aSource.replace(/^file:\/\//, ""); + if (url.scheme == "file" + && this._sources.has(fileUriAbsPath)) { + return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] + } + + if ((!url.path || url.path == "/") + && this._sources.has("/" + aSource)) { + return this.sourcesContent[this._sources.indexOf("/" + aSource)]; + } + } + + throw new Error('"' + aSource + '" is not in the SourceMap.'); + }; + + /** + * Returns the generated line and column information for the original source, + * line, and column positions provided. The only argument is an object with + * the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: The column number in the original source. + * + * and an object is returned with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. + */ + SourceMapConsumer.prototype.generatedPositionFor = + function SourceMapConsumer_generatedPositionFor(aArgs) { + var needle = { + source: util.getArg(aArgs, 'source'), + originalLine: util.getArg(aArgs, 'line'), + originalColumn: util.getArg(aArgs, 'column') + }; + + if (this.sourceRoot) { + needle.source = util.relative(this.sourceRoot, needle.source); + } + + var mapping = this._findMapping(needle, + this._originalMappings, + "originalLine", + "originalColumn", + util.compareByOriginalPositions); + + if (mapping) { + return { + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null) + }; + } + + return { + line: null, + column: null + }; + }; + + SourceMapConsumer.GENERATED_ORDER = 1; + SourceMapConsumer.ORIGINAL_ORDER = 2; + + /** + * Iterate over each mapping between an original source/line/column and a + * generated line/column in this source map. + * + * @param Function aCallback + * The function that is called with each mapping. + * @param Object aContext + * Optional. If specified, this object will be the value of `this` every + * time that `aCallback` is called. + * @param aOrder + * Either `SourceMapConsumer.GENERATED_ORDER` or + * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to + * iterate over the mappings sorted by the generated file's line/column + * order or the original's source/line/column order, respectively. Defaults to + * `SourceMapConsumer.GENERATED_ORDER`. + */ + SourceMapConsumer.prototype.eachMapping = + function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { + var context = aContext || null; + var order = aOrder || SourceMapConsumer.GENERATED_ORDER; + + var mappings; + switch (order) { + case SourceMapConsumer.GENERATED_ORDER: + mappings = this._generatedMappings; + break; + case SourceMapConsumer.ORIGINAL_ORDER: + mappings = this._originalMappings; + break; + default: + throw new Error("Unknown order of iteration."); + } + + var sourceRoot = this.sourceRoot; + mappings.map(function (mapping) { + var source = mapping.source; + if (source && sourceRoot) { + source = util.join(sourceRoot, source); + } + return { + source: source, + generatedLine: mapping.generatedLine, + generatedColumn: mapping.generatedColumn, + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: mapping.name + }; + }).forEach(aCallback, context); + }; + + exports.SourceMapConsumer = SourceMapConsumer; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +define('source-map/source-map-generator', function (require, exports, module) { + + var base64VLQ = require('./base64-vlq'); + var util = require('./util'); + var ArraySet = require('./array-set').ArraySet; + + /** + * An instance of the SourceMapGenerator represents a source map which is + * being built incrementally. To create a new one, you must pass an object + * with the following properties: + * + * - file: The filename of the generated source. + * - sourceRoot: An optional root for all URLs in this source map. + */ + function SourceMapGenerator(aArgs) { + this._file = util.getArg(aArgs, 'file'); + this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); + this._sources = new ArraySet(); + this._names = new ArraySet(); + this._mappings = []; + this._sourcesContents = null; + } + + SourceMapGenerator.prototype._version = 3; + + /** + * Creates a new SourceMapGenerator based on a SourceMapConsumer + * + * @param aSourceMapConsumer The SourceMap. + */ + SourceMapGenerator.fromSourceMap = + function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { + var sourceRoot = aSourceMapConsumer.sourceRoot; + var generator = new SourceMapGenerator({ + file: aSourceMapConsumer.file, + sourceRoot: sourceRoot + }); + aSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: mapping.generatedLine, + column: mapping.generatedColumn + } + }; + + if (mapping.source) { + newMapping.source = mapping.source; + if (sourceRoot) { + newMapping.source = util.relative(sourceRoot, newMapping.source); + } + + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; + + if (mapping.name) { + newMapping.name = mapping.name; + } + } + + generator.addMapping(newMapping); + }); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + generator.setSourceContent(sourceFile, content); + } + }); + return generator; + }; + + /** + * Add a single mapping from original source line and column to the generated + * source's line and column for this source map being created. The mapping + * object should have the following properties: + * + * - generated: An object with the generated line and column positions. + * - original: An object with the original line and column positions. + * - source: The original source file (relative to the sourceRoot). + * - name: An optional original token name for this mapping. + */ + SourceMapGenerator.prototype.addMapping = + function SourceMapGenerator_addMapping(aArgs) { + var generated = util.getArg(aArgs, 'generated'); + var original = util.getArg(aArgs, 'original', null); + var source = util.getArg(aArgs, 'source', null); + var name = util.getArg(aArgs, 'name', null); + + this._validateMapping(generated, original, source, name); + + if (source && !this._sources.has(source)) { + this._sources.add(source); + } + + if (name && !this._names.has(name)) { + this._names.add(name); + } + + this._mappings.push({ + generatedLine: generated.line, + generatedColumn: generated.column, + originalLine: original != null && original.line, + originalColumn: original != null && original.column, + source: source, + name: name + }); + }; + + /** + * Set the source content for a source file. + */ + SourceMapGenerator.prototype.setSourceContent = + function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { + var source = aSourceFile; + if (this._sourceRoot) { + source = util.relative(this._sourceRoot, source); + } + + if (aSourceContent !== null) { + // Add the source content to the _sourcesContents map. + // Create a new _sourcesContents map if the property is null. + if (!this._sourcesContents) { + this._sourcesContents = {}; + } + this._sourcesContents[util.toSetString(source)] = aSourceContent; + } else { + // Remove the source file from the _sourcesContents map. + // If the _sourcesContents map is empty, set the property to null. + delete this._sourcesContents[util.toSetString(source)]; + if (Object.keys(this._sourcesContents).length === 0) { + this._sourcesContents = null; + } + } + }; + + /** + * Applies the mappings of a sub-source-map for a specific source file to the + * source map being generated. Each mapping to the supplied source file is + * rewritten using the supplied source map. Note: The resolution for the + * resulting mappings is the minimium of this map and the supplied map. + * + * @param aSourceMapConsumer The source map to be applied. + * @param aSourceFile Optional. The filename of the source file. + * If omitted, SourceMapConsumer's file property will be used. + */ + SourceMapGenerator.prototype.applySourceMap = + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + // If aSourceFile is omitted, we will use the file property of the SourceMap + if (!aSourceFile) { + aSourceFile = aSourceMapConsumer.file; + } + var sourceRoot = this._sourceRoot; + // Make "aSourceFile" relative if an absolute Url is passed. + if (sourceRoot) { + aSourceFile = util.relative(sourceRoot, aSourceFile); + } + // Applying the SourceMap can add and remove items from the sources and + // the names array. + var newSources = new ArraySet(); + var newNames = new ArraySet(); + + // Find mappings for the "aSourceFile" + this._mappings.forEach(function (mapping) { + if (mapping.source === aSourceFile && mapping.originalLine) { + // Check if it can be mapped by the source map, then update the mapping. + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.originalLine, + column: mapping.originalColumn + }); + if (original.source !== null) { + // Copy mapping + if (sourceRoot) { + mapping.source = util.relative(sourceRoot, original.source); + } else { + mapping.source = original.source; + } + mapping.originalLine = original.line; + mapping.originalColumn = original.column; + if (original.name !== null && mapping.name !== null) { + // Only use the identifier name if it's an identifier + // in both SourceMaps + mapping.name = original.name; + } + } + } + + var source = mapping.source; + if (source && !newSources.has(source)) { + newSources.add(source); + } + + var name = mapping.name; + if (name && !newNames.has(name)) { + newNames.add(name); + } + + }, this); + this._sources = newSources; + this._names = newNames; + + // Copy sourcesContents of applied map. + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + if (sourceRoot) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + this.setSourceContent(sourceFile, content); + } + }, this); + }; + + /** + * A mapping can have one of the three levels of data: + * + * 1. Just the generated position. + * 2. The Generated position, original position, and original source. + * 3. Generated and original position, original source, as well as a name + * token. + * + * To maintain consistency, we validate that any new mapping being added falls + * in to one of these categories. + */ + SourceMapGenerator.prototype._validateMapping = + function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, + aName) { + if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aGenerated.line > 0 && aGenerated.column >= 0 + && !aOriginal && !aSource && !aName) { + // Case 1. + return; + } + else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aOriginal && 'line' in aOriginal && 'column' in aOriginal + && aGenerated.line > 0 && aGenerated.column >= 0 + && aOriginal.line > 0 && aOriginal.column >= 0 + && aSource) { + // Cases 2 and 3. + return; + } + else { + throw new Error('Invalid mapping: ' + JSON.stringify({ + generated: aGenerated, + source: aSource, + orginal: aOriginal, + name: aName + })); + } + }; + + /** + * Serialize the accumulated mappings in to the stream of base 64 VLQs + * specified by the source map format. + */ + SourceMapGenerator.prototype._serializeMappings = + function SourceMapGenerator_serializeMappings() { + var previousGeneratedColumn = 0; + var previousGeneratedLine = 1; + var previousOriginalColumn = 0; + var previousOriginalLine = 0; + var previousName = 0; + var previousSource = 0; + var result = ''; + var mapping; + + // The mappings must be guaranteed to be in sorted order before we start + // serializing them or else the generated line numbers (which are defined + // via the ';' separators) will be all messed up. Note: it might be more + // performant to maintain the sorting as we insert them, rather than as we + // serialize them, but the big O is the same either way. + this._mappings.sort(util.compareByGeneratedPositions); + + for (var i = 0, len = this._mappings.length; i < len; i++) { + mapping = this._mappings[i]; + + if (mapping.generatedLine !== previousGeneratedLine) { + previousGeneratedColumn = 0; + while (mapping.generatedLine !== previousGeneratedLine) { + result += ';'; + previousGeneratedLine++; + } + } + else { + if (i > 0) { + if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { + continue; + } + result += ','; + } + } + + result += base64VLQ.encode(mapping.generatedColumn + - previousGeneratedColumn); + previousGeneratedColumn = mapping.generatedColumn; + + if (mapping.source) { + result += base64VLQ.encode(this._sources.indexOf(mapping.source) + - previousSource); + previousSource = this._sources.indexOf(mapping.source); + + // lines are stored 0-based in SourceMap spec version 3 + result += base64VLQ.encode(mapping.originalLine - 1 + - previousOriginalLine); + previousOriginalLine = mapping.originalLine - 1; + + result += base64VLQ.encode(mapping.originalColumn + - previousOriginalColumn); + previousOriginalColumn = mapping.originalColumn; + + if (mapping.name) { + result += base64VLQ.encode(this._names.indexOf(mapping.name) + - previousName); + previousName = this._names.indexOf(mapping.name); + } + } + } + + return result; + }; + + SourceMapGenerator.prototype._generateSourcesContent = + function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { + return aSources.map(function (source) { + if (!this._sourcesContents) { + return null; + } + if (aSourceRoot) { + source = util.relative(aSourceRoot, source); + } + var key = util.toSetString(source); + return Object.prototype.hasOwnProperty.call(this._sourcesContents, + key) + ? this._sourcesContents[key] + : null; + }, this); + }; + + /** + * Externalize the source map. + */ + SourceMapGenerator.prototype.toJSON = + function SourceMapGenerator_toJSON() { + var map = { + version: this._version, + file: this._file, + sources: this._sources.toArray(), + names: this._names.toArray(), + mappings: this._serializeMappings() + }; + if (this._sourceRoot) { + map.sourceRoot = this._sourceRoot; + } + if (this._sourcesContents) { + map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); + } + + return map; + }; + + /** + * Render the source map being generated to a string. + */ + SourceMapGenerator.prototype.toString = + function SourceMapGenerator_toString() { + return JSON.stringify(this); + }; + + exports.SourceMapGenerator = SourceMapGenerator; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +define('source-map/source-node', function (require, exports, module) { + + var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; + var util = require('./util'); + + /** + * SourceNodes provide a way to abstract over interpolating/concatenating + * snippets of generated JavaScript source code while maintaining the line and + * column information associated with the original source code. + * + * @param aLine The original line number. + * @param aColumn The original column number. + * @param aSource The original source's filename. + * @param aChunks Optional. An array of strings which are snippets of + * generated JS, or other SourceNodes. + * @param aName The original identifier. + */ + function SourceNode(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine === undefined ? null : aLine; + this.column = aColumn === undefined ? null : aColumn; + this.source = aSource === undefined ? null : aSource; + this.name = aName === undefined ? null : aName; + if (aChunks != null) this.add(aChunks); + } + + /** + * Creates a SourceNode from generated code and a SourceMapConsumer. + * + * @param aGeneratedCode The generated code + * @param aSourceMapConsumer The SourceMap for the generated code + */ + SourceNode.fromStringWithSourceMap = + function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { + // The SourceNode we want to fill with the generated code + // and the SourceMap + var node = new SourceNode(); + + // The generated code + // Processed fragments are removed from this array. + var remainingLines = aGeneratedCode.split('\n'); + + // We need to remember the position of "remainingLines" + var lastGeneratedLine = 1, lastGeneratedColumn = 0; + + // The generate SourceNodes we need a code range. + // To extract it current and last mapping is used. + // Here we store the last mapping. + var lastMapping = null; + + aSourceMapConsumer.eachMapping(function (mapping) { + if (lastMapping === null) { + // We add the generated code until the first mapping + // to the SourceNode without any mapping. + // Each line is added as separate string. + while (lastGeneratedLine < mapping.generatedLine) { + node.add(remainingLines.shift() + "\n"); + lastGeneratedLine++; + } + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + node.add(nextLine.substr(0, mapping.generatedColumn)); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + } else { + // We add the code from "lastMapping" to "mapping": + // First check if there is a new line in between. + if (lastGeneratedLine < mapping.generatedLine) { + var code = ""; + // Associate full lines with "lastMapping" + do { + code += remainingLines.shift() + "\n"; + lastGeneratedLine++; + lastGeneratedColumn = 0; + } while (lastGeneratedLine < mapping.generatedLine); + // When we reached the correct line, we add code until we + // reach the correct column too. + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + code += nextLine.substr(0, mapping.generatedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + // Create the SourceNode. + addMappingWithCode(lastMapping, code); + } else { + // There is no new line in between. + // Associate the code between "lastGeneratedColumn" and + // "mapping.generatedColumn" with "lastMapping" + var nextLine = remainingLines[0]; + var code = nextLine.substr(0, mapping.generatedColumn - + lastGeneratedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn - + lastGeneratedColumn); + lastGeneratedColumn = mapping.generatedColumn; + addMappingWithCode(lastMapping, code); + } + } + lastMapping = mapping; + }, this); + // We have processed all mappings. + // Associate the remaining code in the current line with "lastMapping" + // and add the remaining lines without any mapping + addMappingWithCode(lastMapping, remainingLines.join("\n")); + + // Copy sourcesContent into SourceNode + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + node.setSourceContent(sourceFile, content); + } + }); + + return node; + + function addMappingWithCode(mapping, code) { + if (mapping === null || mapping.source === undefined) { + node.add(code); + } else { + node.add(new SourceNode(mapping.originalLine, + mapping.originalColumn, + mapping.source, + code, + mapping.name)); + } + } + }; + + /** + * Add a chunk of generated JS to this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.add = function SourceNode_add(aChunk) { + if (Array.isArray(aChunk)) { + aChunk.forEach(function (chunk) { + this.add(chunk); + }, this); + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + if (aChunk) { + this.children.push(aChunk); + } + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Add a chunk of generated JS to the beginning of this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { + if (Array.isArray(aChunk)) { + for (var i = aChunk.length-1; i >= 0; i--) { + this.prepend(aChunk[i]); + } + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + this.children.unshift(aChunk); + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Walk over the tree of JS snippets in this node and its children. The + * walking function is called once for each snippet of JS and is passed that + * snippet and the its original associated source's line/column location. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walk = function SourceNode_walk(aFn) { + var chunk; + for (var i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; + if (chunk instanceof SourceNode) { + chunk.walk(aFn); + } + else { + if (chunk !== '') { + aFn(chunk, { source: this.source, + line: this.line, + column: this.column, + name: this.name }); + } + } + } + }; + + /** + * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between + * each of `this.children`. + * + * @param aSep The separator. + */ + SourceNode.prototype.join = function SourceNode_join(aSep) { + var newChildren; + var i; + var len = this.children.length; + if (len > 0) { + newChildren = []; + for (i = 0; i < len-1; i++) { + newChildren.push(this.children[i]); + newChildren.push(aSep); + } + newChildren.push(this.children[i]); + this.children = newChildren; + } + return this; + }; + + /** + * Call String.prototype.replace on the very right-most source snippet. Useful + * for trimming whitespace from the end of a source node, etc. + * + * @param aPattern The pattern to replace. + * @param aReplacement The thing to replace the pattern with. + */ + SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { + var lastChild = this.children[this.children.length - 1]; + if (lastChild instanceof SourceNode) { + lastChild.replaceRight(aPattern, aReplacement); + } + else if (typeof lastChild === 'string') { + this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + } + else { + this.children.push(''.replace(aPattern, aReplacement)); + } + return this; + }; + + /** + * Set the source content for a source file. This will be added to the SourceMapGenerator + * in the sourcesContent field. + * + * @param aSourceFile The filename of the source file + * @param aSourceContent The content of the source file + */ + SourceNode.prototype.setSourceContent = + function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; + }; + + /** + * Walk over the tree of SourceNodes. The walking function is called for each + * source file content and is passed the filename and source content. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walkSourceContents = + function SourceNode_walkSourceContents(aFn) { + for (var i = 0, len = this.children.length; i < len; i++) { + if (this.children[i] instanceof SourceNode) { + this.children[i].walkSourceContents(aFn); + } + } + + var sources = Object.keys(this.sourceContents); + for (var i = 0, len = sources.length; i < len; i++) { + aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); + } + }; + + /** + * Return the string representation of this source node. Walks over the tree + * and concatenates all the various snippets together to one string. + */ + SourceNode.prototype.toString = function SourceNode_toString() { + var str = ""; + this.walk(function (chunk) { + str += chunk; + }); + return str; + }; + + /** + * Returns the string representation of this source node along with a source + * map. + */ + SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { + var generated = { + code: "", + line: 1, + column: 0 + }; + var map = new SourceMapGenerator(aArgs); + var sourceMappingActive = false; + var lastOriginalSource = null; + var lastOriginalLine = null; + var lastOriginalColumn = null; + var lastOriginalName = null; + this.walk(function (chunk, original) { + generated.code += chunk; + if (original.source !== null + && original.line !== null + && original.column !== null) { + if(lastOriginalSource !== original.source + || lastOriginalLine !== original.line + || lastOriginalColumn !== original.column + || lastOriginalName !== original.name) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } + lastOriginalSource = original.source; + lastOriginalLine = original.line; + lastOriginalColumn = original.column; + lastOriginalName = original.name; + sourceMappingActive = true; + } else if (sourceMappingActive) { + map.addMapping({ + generated: { + line: generated.line, + column: generated.column + } + }); + lastOriginalSource = null; + sourceMappingActive = false; + } + chunk.split('').forEach(function (ch) { + if (ch === '\n') { + generated.line++; + generated.column = 0; + } else { + generated.column++; + } + }); + }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); + + return { code: generated.code, map: map }; + }; + + exports.SourceNode = SourceNode; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +define('source-map/util', function (require, exports, module) { + + /** + * This is a helper function for getting values from parameter/options + * objects. + * + * @param args The object we are extracting values from + * @param name The name of the property we are getting. + * @param defaultValue An optional value to return if the property is missing + * from the object. If this is not specified and the property is missing, an + * error will be thrown. + */ + function getArg(aArgs, aName, aDefaultValue) { + if (aName in aArgs) { + return aArgs[aName]; + } else if (arguments.length === 3) { + return aDefaultValue; + } else { + throw new Error('"' + aName + '" is a required argument.'); + } + } + exports.getArg = getArg; + + var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + var dataUrlRegexp = /^data:.+\,.+/; + + function urlParse(aUrl) { + var match = aUrl.match(urlRegexp); + if (!match) { + return null; + } + return { + scheme: match[1], + auth: match[3], + host: match[4], + port: match[6], + path: match[7] + }; + } + exports.urlParse = urlParse; + + function urlGenerate(aParsedUrl) { + var url = aParsedUrl.scheme + "://"; + if (aParsedUrl.auth) { + url += aParsedUrl.auth + "@" + } + if (aParsedUrl.host) { + url += aParsedUrl.host; + } + if (aParsedUrl.port) { + url += ":" + aParsedUrl.port + } + if (aParsedUrl.path) { + url += aParsedUrl.path; + } + return url; + } + exports.urlGenerate = urlGenerate; + + function join(aRoot, aPath) { + var url; + + if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { + return aPath; + } + + if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { + url.path = aPath; + return urlGenerate(url); + } + + return aRoot.replace(/\/$/, '') + '/' + aPath; + } + exports.join = join; + + /** + * Because behavior goes wacky when you set `__proto__` on objects, we + * have to prefix all the strings in our set with an arbitrary character. + * + * See https://github.com/mozilla/source-map/pull/31 and + * https://github.com/mozilla/source-map/issues/30 + * + * @param String aStr + */ + function toSetString(aStr) { + return '$' + aStr; + } + exports.toSetString = toSetString; + + function fromSetString(aStr) { + return aStr.substr(1); + } + exports.fromSetString = fromSetString; + + function relative(aRoot, aPath) { + aRoot = aRoot.replace(/\/$/, ''); + + var url = urlParse(aRoot); + if (aPath.charAt(0) == "/" && url && url.path == "/") { + return aPath.slice(1); + } + + return aPath.indexOf(aRoot + '/') === 0 + ? aPath.substr(aRoot.length + 1) + : aPath; + } + exports.relative = relative; + + function strcmp(aStr1, aStr2) { + var s1 = aStr1 || ""; + var s2 = aStr2 || ""; + return (s1 > s2) - (s1 < s2); + } + + /** + * Comparator between two mappings where the original positions are compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same original source/line/column, but different generated + * line and column the same. Useful when searching for a mapping with a + * stubbed out mapping. + */ + function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { + var cmp; + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp || onlyCompareOriginal) { + return cmp; + } + + cmp = strcmp(mappingA.name, mappingB.name); + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + return mappingA.generatedColumn - mappingB.generatedColumn; + }; + exports.compareByOriginalPositions = compareByOriginalPositions; + + /** + * Comparator between two mappings where the generated positions are + * compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same generated line and column, but different + * source/name/original line and column the same. Useful when searching for a + * mapping with a stubbed out mapping. + */ + function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) { + var cmp; + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedColumn - mappingB.generatedColumn; + if (cmp || onlyCompareGenerated) { + return cmp; + } + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp) { + return cmp; + } + + return strcmp(mappingA.name, mappingB.name); + }; + exports.compareByGeneratedPositions = compareByGeneratedPositions; + +}); +define('source-map', function (require, exports, module) { + +/* + * Copyright 2009-2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE.txt or: + * http://opensource.org/licenses/BSD-3-Clause + */ +exports.SourceMapGenerator = require('./source-map/source-map-generator').SourceMapGenerator; +exports.SourceMapConsumer = require('./source-map/source-map-consumer').SourceMapConsumer; +exports.SourceNode = require('./source-map/source-node').SourceNode; + +}); + +//Distributed under the BSD license: +//Copyright 2012 (c) Mihai Bazon +define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], function (exports, MOZ_SourceMap, logger, rjsFile) { +(function(exports, global) { + global["UglifyJS"] = exports; + "use strict"; + function array_to_hash(a) { + var ret = Object.create(null); + for (var i = 0; i < a.length; ++i) ret[a[i]] = true; + return ret; + } + function slice(a, start) { + return Array.prototype.slice.call(a, start || 0); + } + function characters(str) { + return str.split(""); + } + function member(name, array) { + for (var i = array.length; --i >= 0; ) if (array[i] == name) return true; + return false; + } + function find_if(func, array) { + for (var i = 0, n = array.length; i < n; ++i) { + if (func(array[i])) return array[i]; + } + } + function repeat_string(str, i) { + if (i <= 0) return ""; + if (i == 1) return str; + var d = repeat_string(str, i >> 1); + d += d; + if (i & 1) d += str; + return d; + } + function DefaultsError(msg, defs) { + this.msg = msg; + this.defs = defs; + } + function defaults(args, defs, croak) { + if (args === true) args = {}; + var ret = args || {}; + if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i)) throw new DefaultsError("`" + i + "` is not a supported option", defs); + for (var i in defs) if (defs.hasOwnProperty(i)) { + ret[i] = args && args.hasOwnProperty(i) ? args[i] : defs[i]; + } + return ret; + } + function merge(obj, ext) { + for (var i in ext) if (ext.hasOwnProperty(i)) { + obj[i] = ext[i]; + } + return obj; + } + function noop() {} + var MAP = function() { + function MAP(a, f, backwards) { + var ret = [], top = [], i; + function doit() { + var val = f(a[i], i); + var is_last = val instanceof Last; + if (is_last) val = val.v; + if (val instanceof AtTop) { + val = val.v; + if (val instanceof Splice) { + top.push.apply(top, backwards ? val.v.slice().reverse() : val.v); + } else { + top.push(val); + } + } else if (val !== skip) { + if (val instanceof Splice) { + ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v); + } else { + ret.push(val); + } + } + return is_last; + } + if (a instanceof Array) { + if (backwards) { + for (i = a.length; --i >= 0; ) if (doit()) break; + ret.reverse(); + top.reverse(); + } else { + for (i = 0; i < a.length; ++i) if (doit()) break; + } + } else { + for (i in a) if (a.hasOwnProperty(i)) if (doit()) break; + } + return top.concat(ret); + } + MAP.at_top = function(val) { + return new AtTop(val); + }; + MAP.splice = function(val) { + return new Splice(val); + }; + MAP.last = function(val) { + return new Last(val); + }; + var skip = MAP.skip = {}; + function AtTop(val) { + this.v = val; + } + function Splice(val) { + this.v = val; + } + function Last(val) { + this.v = val; + } + return MAP; + }(); + function push_uniq(array, el) { + if (array.indexOf(el) < 0) array.push(el); + } + function string_template(text, props) { + return text.replace(/\{(.+?)\}/g, function(str, p) { + return props[p]; + }); + } + function remove(array, el) { + for (var i = array.length; --i >= 0; ) { + if (array[i] === el) array.splice(i, 1); + } + } + function mergeSort(array, cmp) { + if (array.length < 2) return array.slice(); + function merge(a, b) { + var r = [], ai = 0, bi = 0, i = 0; + while (ai < a.length && bi < b.length) { + cmp(a[ai], b[bi]) <= 0 ? r[i++] = a[ai++] : r[i++] = b[bi++]; + } + if (ai < a.length) r.push.apply(r, a.slice(ai)); + if (bi < b.length) r.push.apply(r, b.slice(bi)); + return r; + } + function _ms(a) { + if (a.length <= 1) return a; + var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m); + left = _ms(left); + right = _ms(right); + return merge(left, right); + } + return _ms(array); + } + function set_difference(a, b) { + return a.filter(function(el) { + return b.indexOf(el) < 0; + }); + } + function set_intersection(a, b) { + return a.filter(function(el) { + return b.indexOf(el) >= 0; + }); + } + function makePredicate(words) { + if (!(words instanceof Array)) words = words.split(" "); + var f = "", cats = []; + out: for (var i = 0; i < words.length; ++i) { + for (var j = 0; j < cats.length; ++j) if (cats[j][0].length == words[i].length) { + cats[j].push(words[i]); + continue out; + } + cats.push([ words[i] ]); + } + function compareTo(arr) { + if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";"; + f += "switch(str){"; + for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":"; + f += "return true}return false;"; + } + if (cats.length > 3) { + cats.sort(function(a, b) { + return b.length - a.length; + }); + f += "switch(str.length){"; + for (var i = 0; i < cats.length; ++i) { + var cat = cats[i]; + f += "case " + cat[0].length + ":"; + compareTo(cat); + } + f += "}"; + } else { + compareTo(words); + } + return new Function("str", f); + } + function all(array, predicate) { + for (var i = array.length; --i >= 0; ) if (!predicate(array[i])) return false; + return true; + } + function Dictionary() { + this._values = Object.create(null); + this._size = 0; + } + Dictionary.prototype = { + set: function(key, val) { + if (!this.has(key)) ++this._size; + this._values["$" + key] = val; + return this; + }, + add: function(key, val) { + if (this.has(key)) { + this.get(key).push(val); + } else { + this.set(key, [ val ]); + } + return this; + }, + get: function(key) { + return this._values["$" + key]; + }, + del: function(key) { + if (this.has(key)) { + --this._size; + delete this._values["$" + key]; + } + return this; + }, + has: function(key) { + return "$" + key in this._values; + }, + each: function(f) { + for (var i in this._values) f(this._values[i], i.substr(1)); + }, + size: function() { + return this._size; + }, + map: function(f) { + var ret = []; + for (var i in this._values) ret.push(f(this._values[i], i.substr(1))); + return ret; + } + }; + "use strict"; + function DEFNODE(type, props, methods, base) { + if (arguments.length < 4) base = AST_Node; + if (!props) props = []; else props = props.split(/\s+/); + var self_props = props; + if (base && base.PROPS) props = props.concat(base.PROPS); + var code = "return function AST_" + type + "(props){ if (props) { "; + for (var i = props.length; --i >= 0; ) { + code += "this." + props[i] + " = props." + props[i] + ";"; + } + var proto = base && new base(); + if (proto && proto.initialize || methods && methods.initialize) code += "this.initialize();"; + code += "}}"; + var ctor = new Function(code)(); + if (proto) { + ctor.prototype = proto; + ctor.BASE = base; + } + if (base) base.SUBCLASSES.push(ctor); + ctor.prototype.CTOR = ctor; + ctor.PROPS = props || null; + ctor.SELF_PROPS = self_props; + ctor.SUBCLASSES = []; + if (type) { + ctor.prototype.TYPE = ctor.TYPE = type; + } + if (methods) for (i in methods) if (methods.hasOwnProperty(i)) { + if (/^\$/.test(i)) { + ctor[i.substr(1)] = methods[i]; + } else { + ctor.prototype[i] = methods[i]; + } + } + ctor.DEFMETHOD = function(name, method) { + this.prototype[name] = method; + }; + return ctor; + } + var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", {}, null); + var AST_Node = DEFNODE("Node", "start end", { + clone: function() { + return new this.CTOR(this); + }, + $documentation: "Base class of all AST nodes", + $propdoc: { + start: "[AST_Token] The first token of this node", + end: "[AST_Token] The last token of this node" + }, + _walk: function(visitor) { + return visitor._visit(this); + }, + walk: function(visitor) { + return this._walk(visitor); + } + }, null); + AST_Node.warn_function = null; + AST_Node.warn = function(txt, props) { + if (AST_Node.warn_function) AST_Node.warn_function(string_template(txt, props)); + }; + var AST_Statement = DEFNODE("Statement", null, { + $documentation: "Base class of all statements" + }); + var AST_Debugger = DEFNODE("Debugger", null, { + $documentation: "Represents a debugger statement" + }, AST_Statement); + var AST_Directive = DEFNODE("Directive", "value scope", { + $documentation: 'Represents a directive, like "use strict";', + $propdoc: { + value: "[string] The value of this directive as a plain string (it's not an AST_String!)", + scope: "[AST_Scope/S] The scope that this directive affects" + } + }, AST_Statement); + var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", { + $documentation: "A statement consisting of an expression, i.e. a = 1 + 2", + $propdoc: { + body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.body._walk(visitor); + }); + } + }, AST_Statement); + function walk_body(node, visitor) { + if (node.body instanceof AST_Statement) { + node.body._walk(visitor); + } else node.body.forEach(function(stat) { + stat._walk(visitor); + }); + } + var AST_Block = DEFNODE("Block", "body", { + $documentation: "A body of statements (usually bracketed)", + $propdoc: { + body: "[AST_Statement*] an array of statements" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + walk_body(this, visitor); + }); + } + }, AST_Statement); + var AST_BlockStatement = DEFNODE("BlockStatement", null, { + $documentation: "A block statement" + }, AST_Block); + var AST_EmptyStatement = DEFNODE("EmptyStatement", null, { + $documentation: "The empty statement (empty block or simply a semicolon)", + _walk: function(visitor) { + return visitor._visit(this); + } + }, AST_Statement); + var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", { + $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`", + $propdoc: { + body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.body._walk(visitor); + }); + } + }, AST_Statement); + var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", { + $documentation: "Statement with a label", + $propdoc: { + label: "[AST_Label] a label definition" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.label._walk(visitor); + this.body._walk(visitor); + }); + } + }, AST_StatementWithBody); + var AST_DWLoop = DEFNODE("DWLoop", "condition", { + $documentation: "Base class for do/while statements", + $propdoc: { + condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.condition._walk(visitor); + this.body._walk(visitor); + }); + } + }, AST_StatementWithBody); + var AST_Do = DEFNODE("Do", null, { + $documentation: "A `do` statement" + }, AST_DWLoop); + var AST_While = DEFNODE("While", null, { + $documentation: "A `while` statement" + }, AST_DWLoop); + var AST_For = DEFNODE("For", "init condition step", { + $documentation: "A `for` statement", + $propdoc: { + init: "[AST_Node?] the `for` initialization code, or null if empty", + condition: "[AST_Node?] the `for` termination clause, or null if empty", + step: "[AST_Node?] the `for` update clause, or null if empty" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + if (this.init) this.init._walk(visitor); + if (this.condition) this.condition._walk(visitor); + if (this.step) this.step._walk(visitor); + this.body._walk(visitor); + }); + } + }, AST_StatementWithBody); + var AST_ForIn = DEFNODE("ForIn", "init name object", { + $documentation: "A `for ... in` statement", + $propdoc: { + init: "[AST_Node] the `for/in` initialization code", + name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var", + object: "[AST_Node] the object that we're looping through" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.init._walk(visitor); + this.object._walk(visitor); + this.body._walk(visitor); + }); + } + }, AST_StatementWithBody); + var AST_With = DEFNODE("With", "expression", { + $documentation: "A `with` statement", + $propdoc: { + expression: "[AST_Node] the `with` expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + this.body._walk(visitor); + }); + } + }, AST_StatementWithBody); + var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", { + $documentation: "Base class for all statements introducing a lexical scope", + $propdoc: { + directives: "[string*/S] an array of directives declared in this scope", + variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", + functions: "[Object/S] like `variables`, but only lists function declarations", + uses_with: "[boolean/S] tells whether this scope uses the `with` statement", + uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", + parent_scope: "[AST_Scope?/S] link to the parent scope", + enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", + cname: "[integer/S] current index for mangling variables (used internally by the mangler)" + } + }, AST_Block); + var AST_Toplevel = DEFNODE("Toplevel", "globals", { + $documentation: "The toplevel scope", + $propdoc: { + globals: "[Object/S] a map of name -> SymbolDef for all undeclared names" + }, + wrap_enclose: function(arg_parameter_pairs) { + var self = this; + var args = []; + var parameters = []; + arg_parameter_pairs.forEach(function(pair) { + var split = pair.split(":"); + args.push(split[0]); + parameters.push(split[1]); + }); + var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")"; + wrapped_tl = parse(wrapped_tl); + wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) { + if (node instanceof AST_Directive && node.value == "$ORIG") { + return MAP.splice(self.body); + } + })); + return wrapped_tl; + }, + wrap_commonjs: function(name, export_all) { + var self = this; + var to_export = []; + if (export_all) { + self.figure_out_scope(); + self.walk(new TreeWalker(function(node) { + if (node instanceof AST_SymbolDeclaration && node.definition().global) { + if (!find_if(function(n) { + return n.name == node.name; + }, to_export)) to_export.push(node); + } + })); + } + var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))"; + wrapped_tl = parse(wrapped_tl); + wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) { + if (node instanceof AST_SimpleStatement) { + node = node.body; + if (node instanceof AST_String) switch (node.getValue()) { + case "$ORIG": + return MAP.splice(self.body); + + case "$EXPORTS": + var body = []; + to_export.forEach(function(sym) { + body.push(new AST_SimpleStatement({ + body: new AST_Assign({ + left: new AST_Sub({ + expression: new AST_SymbolRef({ + name: "exports" + }), + property: new AST_String({ + value: sym.name + }) + }), + operator: "=", + right: new AST_SymbolRef(sym) + }) + })); + }); + return MAP.splice(body); + } + } + })); + return wrapped_tl; + } + }, AST_Scope); + var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", { + $documentation: "Base class for functions", + $propdoc: { + name: "[AST_SymbolDeclaration?] the name of this function", + argnames: "[AST_SymbolFunarg*] array of function arguments", + uses_arguments: "[boolean/S] tells whether this function accesses the arguments array" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + if (this.name) this.name._walk(visitor); + this.argnames.forEach(function(arg) { + arg._walk(visitor); + }); + walk_body(this, visitor); + }); + } + }, AST_Scope); + var AST_Accessor = DEFNODE("Accessor", null, { + $documentation: "A setter/getter function" + }, AST_Lambda); + var AST_Function = DEFNODE("Function", null, { + $documentation: "A function expression" + }, AST_Lambda); + var AST_Defun = DEFNODE("Defun", null, { + $documentation: "A function definition" + }, AST_Lambda); + var AST_Jump = DEFNODE("Jump", null, { + $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)" + }, AST_Statement); + var AST_Exit = DEFNODE("Exit", "value", { + $documentation: "Base class for “exits” (`return` and `throw`)", + $propdoc: { + value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return" + }, + _walk: function(visitor) { + return visitor._visit(this, this.value && function() { + this.value._walk(visitor); + }); + } + }, AST_Jump); + var AST_Return = DEFNODE("Return", null, { + $documentation: "A `return` statement" + }, AST_Exit); + var AST_Throw = DEFNODE("Throw", null, { + $documentation: "A `throw` statement" + }, AST_Exit); + var AST_LoopControl = DEFNODE("LoopControl", "label", { + $documentation: "Base class for loop control statements (`break` and `continue`)", + $propdoc: { + label: "[AST_LabelRef?] the label, or null if none" + }, + _walk: function(visitor) { + return visitor._visit(this, this.label && function() { + this.label._walk(visitor); + }); + } + }, AST_Jump); + var AST_Break = DEFNODE("Break", null, { + $documentation: "A `break` statement" + }, AST_LoopControl); + var AST_Continue = DEFNODE("Continue", null, { + $documentation: "A `continue` statement" + }, AST_LoopControl); + var AST_If = DEFNODE("If", "condition alternative", { + $documentation: "A `if` statement", + $propdoc: { + condition: "[AST_Node] the `if` condition", + alternative: "[AST_Statement?] the `else` part, or null if not present" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.condition._walk(visitor); + this.body._walk(visitor); + if (this.alternative) this.alternative._walk(visitor); + }); + } + }, AST_StatementWithBody); + var AST_Switch = DEFNODE("Switch", "expression", { + $documentation: "A `switch` statement", + $propdoc: { + expression: "[AST_Node] the `switch` “discriminant”" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + walk_body(this, visitor); + }); + } + }, AST_Block); + var AST_SwitchBranch = DEFNODE("SwitchBranch", null, { + $documentation: "Base class for `switch` branches" + }, AST_Block); + var AST_Default = DEFNODE("Default", null, { + $documentation: "A `default` switch branch" + }, AST_SwitchBranch); + var AST_Case = DEFNODE("Case", "expression", { + $documentation: "A `case` switch branch", + $propdoc: { + expression: "[AST_Node] the `case` expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + walk_body(this, visitor); + }); + } + }, AST_SwitchBranch); + var AST_Try = DEFNODE("Try", "bcatch bfinally", { + $documentation: "A `try` statement", + $propdoc: { + bcatch: "[AST_Catch?] the catch block, or null if not present", + bfinally: "[AST_Finally?] the finally block, or null if not present" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + walk_body(this, visitor); + if (this.bcatch) this.bcatch._walk(visitor); + if (this.bfinally) this.bfinally._walk(visitor); + }); + } + }, AST_Block); + var AST_Catch = DEFNODE("Catch", "argname", { + $documentation: "A `catch` node; only makes sense as part of a `try` statement", + $propdoc: { + argname: "[AST_SymbolCatch] symbol for the exception" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.argname._walk(visitor); + walk_body(this, visitor); + }); + } + }, AST_Block); + var AST_Finally = DEFNODE("Finally", null, { + $documentation: "A `finally` node; only makes sense as part of a `try` statement" + }, AST_Block); + var AST_Definitions = DEFNODE("Definitions", "definitions", { + $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)", + $propdoc: { + definitions: "[AST_VarDef*] array of variable definitions" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.definitions.forEach(function(def) { + def._walk(visitor); + }); + }); + } + }, AST_Statement); + var AST_Var = DEFNODE("Var", null, { + $documentation: "A `var` statement" + }, AST_Definitions); + var AST_Const = DEFNODE("Const", null, { + $documentation: "A `const` statement" + }, AST_Definitions); + var AST_VarDef = DEFNODE("VarDef", "name value", { + $documentation: "A variable declaration; only appears in a AST_Definitions node", + $propdoc: { + name: "[AST_SymbolVar|AST_SymbolConst] name of the variable", + value: "[AST_Node?] initializer, or null of there's no initializer" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.name._walk(visitor); + if (this.value) this.value._walk(visitor); + }); + } + }); + var AST_Call = DEFNODE("Call", "expression args", { + $documentation: "A function call expression", + $propdoc: { + expression: "[AST_Node] expression to invoke as function", + args: "[AST_Node*] array of arguments" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + this.args.forEach(function(arg) { + arg._walk(visitor); + }); + }); + } + }); + var AST_New = DEFNODE("New", null, { + $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties" + }, AST_Call); + var AST_Seq = DEFNODE("Seq", "car cdr", { + $documentation: "A sequence expression (two comma-separated expressions)", + $propdoc: { + car: "[AST_Node] first element in sequence", + cdr: "[AST_Node] second element in sequence" + }, + $cons: function(x, y) { + var seq = new AST_Seq(x); + seq.car = x; + seq.cdr = y; + return seq; + }, + $from_array: function(array) { + if (array.length == 0) return null; + if (array.length == 1) return array[0].clone(); + var list = null; + for (var i = array.length; --i >= 0; ) { + list = AST_Seq.cons(array[i], list); + } + var p = list; + while (p) { + if (p.cdr && !p.cdr.cdr) { + p.cdr = p.cdr.car; + break; + } + p = p.cdr; + } + return list; + }, + to_array: function() { + var p = this, a = []; + while (p) { + a.push(p.car); + if (p.cdr && !(p.cdr instanceof AST_Seq)) { + a.push(p.cdr); + break; + } + p = p.cdr; + } + return a; + }, + add: function(node) { + var p = this; + while (p) { + if (!(p.cdr instanceof AST_Seq)) { + var cell = AST_Seq.cons(p.cdr, node); + return p.cdr = cell; + } + p = p.cdr; + } + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.car._walk(visitor); + if (this.cdr) this.cdr._walk(visitor); + }); + } + }); + var AST_PropAccess = DEFNODE("PropAccess", "expression property", { + $documentation: 'Base class for property access expressions, i.e. `a.foo` or `a["foo"]`', + $propdoc: { + expression: "[AST_Node] the “container” expression", + property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node" + } + }); + var AST_Dot = DEFNODE("Dot", null, { + $documentation: "A dotted property access expression", + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + }); + } + }, AST_PropAccess); + var AST_Sub = DEFNODE("Sub", null, { + $documentation: 'Index-style property access, i.e. `a["foo"]`', + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + this.property._walk(visitor); + }); + } + }, AST_PropAccess); + var AST_Unary = DEFNODE("Unary", "operator expression", { + $documentation: "Base class for unary expressions", + $propdoc: { + operator: "[string] the operator", + expression: "[AST_Node] expression that this unary operator applies to" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + }); + } + }); + var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, { + $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`" + }, AST_Unary); + var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, { + $documentation: "Unary postfix expression, i.e. `i++`" + }, AST_Unary); + var AST_Binary = DEFNODE("Binary", "left operator right", { + $documentation: "Binary expression, i.e. `a + b`", + $propdoc: { + left: "[AST_Node] left-hand side expression", + operator: "[string] the operator", + right: "[AST_Node] right-hand side expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.left._walk(visitor); + this.right._walk(visitor); + }); + } + }); + var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", { + $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`", + $propdoc: { + condition: "[AST_Node]", + consequent: "[AST_Node]", + alternative: "[AST_Node]" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.condition._walk(visitor); + this.consequent._walk(visitor); + this.alternative._walk(visitor); + }); + } + }); + var AST_Assign = DEFNODE("Assign", null, { + $documentation: "An assignment expression — `a = b + 5`" + }, AST_Binary); + var AST_Array = DEFNODE("Array", "elements", { + $documentation: "An array literal", + $propdoc: { + elements: "[AST_Node*] array of elements" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.elements.forEach(function(el) { + el._walk(visitor); + }); + }); + } + }); + var AST_Object = DEFNODE("Object", "properties", { + $documentation: "An object literal", + $propdoc: { + properties: "[AST_ObjectProperty*] array of properties" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.properties.forEach(function(prop) { + prop._walk(visitor); + }); + }); + } + }); + var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", { + $documentation: "Base class for literal object properties", + $propdoc: { + key: "[string] the property name; it's always a plain string in our AST, no matter if it was a string, number or identifier in original code", + value: "[AST_Node] property value. For setters and getters this is an AST_Function." + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.value._walk(visitor); + }); + } + }); + var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, { + $documentation: "A key: value object property" + }, AST_ObjectProperty); + var AST_ObjectSetter = DEFNODE("ObjectSetter", null, { + $documentation: "An object setter property" + }, AST_ObjectProperty); + var AST_ObjectGetter = DEFNODE("ObjectGetter", null, { + $documentation: "An object getter property" + }, AST_ObjectProperty); + var AST_Symbol = DEFNODE("Symbol", "scope name thedef", { + $propdoc: { + name: "[string] name of this symbol", + scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)", + thedef: "[SymbolDef/S] the definition of this symbol" + }, + $documentation: "Base class for all symbols" + }); + var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, { + $documentation: "The name of a property accessor (setter/getter function)" + }, AST_Symbol); + var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", { + $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)", + $propdoc: { + init: "[AST_Node*/S] array of initializers for this declaration." + } + }, AST_Symbol); + var AST_SymbolVar = DEFNODE("SymbolVar", null, { + $documentation: "Symbol defining a variable" + }, AST_SymbolDeclaration); + var AST_SymbolConst = DEFNODE("SymbolConst", null, { + $documentation: "A constant declaration" + }, AST_SymbolDeclaration); + var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, { + $documentation: "Symbol naming a function argument" + }, AST_SymbolVar); + var AST_SymbolDefun = DEFNODE("SymbolDefun", null, { + $documentation: "Symbol defining a function" + }, AST_SymbolDeclaration); + var AST_SymbolLambda = DEFNODE("SymbolLambda", null, { + $documentation: "Symbol naming a function expression" + }, AST_SymbolDeclaration); + var AST_SymbolCatch = DEFNODE("SymbolCatch", null, { + $documentation: "Symbol naming the exception in catch" + }, AST_SymbolDeclaration); + var AST_Label = DEFNODE("Label", "references", { + $documentation: "Symbol naming a label (declaration)", + $propdoc: { + references: "[AST_LabelRef*] a list of nodes referring to this label" + } + }, AST_Symbol); + var AST_SymbolRef = DEFNODE("SymbolRef", null, { + $documentation: "Reference to some symbol (not definition/declaration)" + }, AST_Symbol); + var AST_LabelRef = DEFNODE("LabelRef", null, { + $documentation: "Reference to a label symbol" + }, AST_Symbol); + var AST_This = DEFNODE("This", null, { + $documentation: "The `this` symbol" + }, AST_Symbol); + var AST_Constant = DEFNODE("Constant", null, { + $documentation: "Base class for all constants", + getValue: function() { + return this.value; + } + }); + var AST_String = DEFNODE("String", "value", { + $documentation: "A string literal", + $propdoc: { + value: "[string] the contents of this string" + } + }, AST_Constant); + var AST_Number = DEFNODE("Number", "value", { + $documentation: "A number literal", + $propdoc: { + value: "[number] the numeric value" + } + }, AST_Constant); + var AST_RegExp = DEFNODE("RegExp", "value", { + $documentation: "A regexp literal", + $propdoc: { + value: "[RegExp] the actual regexp" + } + }, AST_Constant); + var AST_Atom = DEFNODE("Atom", null, { + $documentation: "Base class for atoms" + }, AST_Constant); + var AST_Null = DEFNODE("Null", null, { + $documentation: "The `null` atom", + value: null + }, AST_Atom); + var AST_NaN = DEFNODE("NaN", null, { + $documentation: "The impossible value", + value: 0 / 0 + }, AST_Atom); + var AST_Undefined = DEFNODE("Undefined", null, { + $documentation: "The `undefined` value", + value: function() {}() + }, AST_Atom); + var AST_Hole = DEFNODE("Hole", null, { + $documentation: "A hole in an array", + value: function() {}() + }, AST_Atom); + var AST_Infinity = DEFNODE("Infinity", null, { + $documentation: "The `Infinity` value", + value: 1 / 0 + }, AST_Atom); + var AST_Boolean = DEFNODE("Boolean", null, { + $documentation: "Base class for booleans" + }, AST_Atom); + var AST_False = DEFNODE("False", null, { + $documentation: "The `false` atom", + value: false + }, AST_Boolean); + var AST_True = DEFNODE("True", null, { + $documentation: "The `true` atom", + value: true + }, AST_Boolean); + function TreeWalker(callback) { + this.visit = callback; + this.stack = []; + } + TreeWalker.prototype = { + _visit: function(node, descend) { + this.stack.push(node); + var ret = this.visit(node, descend ? function() { + descend.call(node); + } : noop); + if (!ret && descend) { + descend.call(node); + } + this.stack.pop(); + return ret; + }, + parent: function(n) { + return this.stack[this.stack.length - 2 - (n || 0)]; + }, + push: function(node) { + this.stack.push(node); + }, + pop: function() { + return this.stack.pop(); + }, + self: function() { + return this.stack[this.stack.length - 1]; + }, + find_parent: function(type) { + var stack = this.stack; + for (var i = stack.length; --i >= 0; ) { + var x = stack[i]; + if (x instanceof type) return x; + } + }, + has_directive: function(type) { + return this.find_parent(AST_Scope).has_directive(type); + }, + in_boolean_context: function() { + var stack = this.stack; + var i = stack.length, self = stack[--i]; + while (i > 0) { + var p = stack[--i]; + if (p instanceof AST_If && p.condition === self || p instanceof AST_Conditional && p.condition === self || p instanceof AST_DWLoop && p.condition === self || p instanceof AST_For && p.condition === self || p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) { + return true; + } + if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||"))) return false; + self = p; + } + }, + loopcontrol_target: function(label) { + var stack = this.stack; + if (label) { + for (var i = stack.length; --i >= 0; ) { + var x = stack[i]; + if (x instanceof AST_LabeledStatement && x.label.name == label.name) { + return x.body; + } + } + } else { + for (var i = stack.length; --i >= 0; ) { + var x = stack[i]; + if (x instanceof AST_Switch || x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) return x; + } + } + } + }; + "use strict"; + var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with"; + var KEYWORDS_ATOM = "false null true"; + var RESERVED_WORDS = "abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile" + " " + KEYWORDS_ATOM + " " + KEYWORDS; + var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case"; + KEYWORDS = makePredicate(KEYWORDS); + RESERVED_WORDS = makePredicate(RESERVED_WORDS); + KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION); + KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM); + var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^")); + var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; + var RE_OCT_NUMBER = /^0[0-7]+$/; + var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; + var OPERATORS = makePredicate([ "in", "instanceof", "typeof", "new", "void", "delete", "++", "--", "+", "-", "!", "~", "&", "|", "^", "*", "/", "%", ">>", "<<", ">>>", "<", ">", "<=", ">=", "==", "===", "!=", "!==", "?", "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=", "&&", "||" ]); + var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000")); + var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:")); + var PUNC_CHARS = makePredicate(characters("[]{}(),;:")); + var REGEXP_MODIFIERS = makePredicate(characters("gmsiy")); + var UNICODE = { + letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"), + non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"), + space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"), + connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]") + }; + function is_letter(code) { + return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 170 && UNICODE.letter.test(String.fromCharCode(code)); + } + function is_digit(code) { + return code >= 48 && code <= 57; + } + function is_alphanumeric_char(code) { + return is_digit(code) || is_letter(code); + } + function is_unicode_combining_mark(ch) { + return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch); + } + function is_unicode_connector_punctuation(ch) { + return UNICODE.connector_punctuation.test(ch); + } + function is_identifier(name) { + return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name); + } + function is_identifier_start(code) { + return code == 36 || code == 95 || is_letter(code); + } + function is_identifier_char(ch) { + var code = ch.charCodeAt(0); + return is_identifier_start(code) || is_digit(code) || code == 8204 || code == 8205 || is_unicode_combining_mark(ch) || is_unicode_connector_punctuation(ch); + } + function is_identifier_string(str) { + var i = str.length; + if (i == 0) return false; + if (is_digit(str.charCodeAt(0))) return false; + while (--i >= 0) { + if (!is_identifier_char(str.charAt(i))) return false; + } + return true; + } + function parse_js_number(num) { + if (RE_HEX_NUMBER.test(num)) { + return parseInt(num.substr(2), 16); + } else if (RE_OCT_NUMBER.test(num)) { + return parseInt(num.substr(1), 8); + } else if (RE_DEC_NUMBER.test(num)) { + return parseFloat(num); + } + } + function JS_Parse_Error(message, line, col, pos) { + this.message = message; + this.line = line; + this.col = col; + this.pos = pos; + this.stack = new Error().stack; + } + JS_Parse_Error.prototype.toString = function() { + return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack; + }; + function js_error(message, filename, line, col, pos) { + throw new JS_Parse_Error(message, line, col, pos); + } + function is_token(token, type, val) { + return token.type == type && (val == null || token.value == val); + } + var EX_EOF = {}; + function tokenizer($TEXT, filename) { + var S = { + text: $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ""), + filename: filename, + pos: 0, + tokpos: 0, + line: 1, + tokline: 0, + col: 0, + tokcol: 0, + newline_before: false, + regex_allowed: false, + comments_before: [] + }; + function peek() { + return S.text.charAt(S.pos); + } + function next(signal_eof, in_string) { + var ch = S.text.charAt(S.pos++); + if (signal_eof && !ch) throw EX_EOF; + if (ch == "\n") { + S.newline_before = S.newline_before || !in_string; + ++S.line; + S.col = 0; + } else { + ++S.col; + } + return ch; + } + function find(what, signal_eof) { + var pos = S.text.indexOf(what, S.pos); + if (signal_eof && pos == -1) throw EX_EOF; + return pos; + } + function start_token() { + S.tokline = S.line; + S.tokcol = S.col; + S.tokpos = S.pos; + } + function token(type, value, is_comment) { + S.regex_allowed = type == "operator" && !UNARY_POSTFIX(value) || type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value) || type == "punc" && PUNC_BEFORE_EXPRESSION(value); + var ret = { + type: type, + value: value, + line: S.tokline, + col: S.tokcol, + pos: S.tokpos, + endpos: S.pos, + nlb: S.newline_before, + file: filename + }; + if (!is_comment) { + ret.comments_before = S.comments_before; + S.comments_before = []; + for (var i = 0, len = ret.comments_before.length; i < len; i++) { + ret.nlb = ret.nlb || ret.comments_before[i].nlb; + } + } + S.newline_before = false; + return new AST_Token(ret); + } + function skip_whitespace() { + while (WHITESPACE_CHARS(peek())) next(); + } + function read_while(pred) { + var ret = "", ch, i = 0; + while ((ch = peek()) && pred(ch, i++)) ret += next(); + return ret; + } + function parse_error(err) { + js_error(err, filename, S.tokline, S.tokcol, S.tokpos); + } + function read_num(prefix) { + var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; + var num = read_while(function(ch, i) { + var code = ch.charCodeAt(0); + switch (code) { + case 120: + case 88: + return has_x ? false : has_x = true; + + case 101: + case 69: + return has_x ? true : has_e ? false : has_e = after_e = true; + + case 45: + return after_e || i == 0 && !prefix; + + case 43: + return after_e; + + case after_e = false, 46: + return !has_dot && !has_x && !has_e ? has_dot = true : false; + } + return is_alphanumeric_char(code); + }); + if (prefix) num = prefix + num; + var valid = parse_js_number(num); + if (!isNaN(valid)) { + return token("num", valid); + } else { + parse_error("Invalid syntax: " + num); + } + } + function read_escaped_char(in_string) { + var ch = next(true, in_string); + switch (ch.charCodeAt(0)) { + case 110: + return "\n"; + + case 114: + return "\r"; + + case 116: + return " "; + + case 98: + return "\b"; + + case 118: + return " "; + + case 102: + return "\f"; + + case 48: + return "\x00"; + + case 120: + return String.fromCharCode(hex_bytes(2)); + + case 117: + return String.fromCharCode(hex_bytes(4)); + + case 10: + return ""; + + default: + return ch; + } + } + function hex_bytes(n) { + var num = 0; + for (;n > 0; --n) { + var digit = parseInt(next(true), 16); + if (isNaN(digit)) parse_error("Invalid hex-character pattern in string"); + num = num << 4 | digit; + } + return num; + } + var read_string = with_eof_error("Unterminated string constant", function() { + var quote = next(), ret = ""; + for (;;) { + var ch = next(true); + if (ch == "\\") { + var octal_len = 0, first = null; + ch = read_while(function(ch) { + if (ch >= "0" && ch <= "7") { + if (!first) { + first = ch; + return ++octal_len; + } else if (first <= "3" && octal_len <= 2) return ++octal_len; else if (first >= "4" && octal_len <= 1) return ++octal_len; + } + return false; + }); + if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8)); else ch = read_escaped_char(true); + } else if (ch == quote) break; + ret += ch; + } + return token("string", ret); + }); + function read_line_comment() { + next(); + var i = find("\n"), ret; + if (i == -1) { + ret = S.text.substr(S.pos); + S.pos = S.text.length; + } else { + ret = S.text.substring(S.pos, i); + S.pos = i; + } + return token("comment1", ret, true); + } + var read_multiline_comment = with_eof_error("Unterminated multiline comment", function() { + next(); + var i = find("*/", true); + var text = S.text.substring(S.pos, i); + var a = text.split("\n"), n = a.length; + S.pos = i + 2; + S.line += n - 1; + if (n > 1) S.col = a[n - 1].length; else S.col += a[n - 1].length; + S.col += 2; + S.newline_before = S.newline_before || text.indexOf("\n") >= 0; + return token("comment2", text, true); + }); + function read_name() { + var backslash = false, name = "", ch, escaped = false, hex; + while ((ch = peek()) != null) { + if (!backslash) { + if (ch == "\\") escaped = backslash = true, next(); else if (is_identifier_char(ch)) name += next(); else break; + } else { + if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); + ch = read_escaped_char(); + if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); + name += ch; + backslash = false; + } + } + if (KEYWORDS(name) && escaped) { + hex = name.charCodeAt(0).toString(16).toUpperCase(); + name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1); + } + return name; + } + var read_regexp = with_eof_error("Unterminated regular expression", function(regexp) { + var prev_backslash = false, ch, in_class = false; + while (ch = next(true)) if (prev_backslash) { + regexp += "\\" + ch; + prev_backslash = false; + } else if (ch == "[") { + in_class = true; + regexp += ch; + } else if (ch == "]" && in_class) { + in_class = false; + regexp += ch; + } else if (ch == "/" && !in_class) { + break; + } else if (ch == "\\") { + prev_backslash = true; + } else { + regexp += ch; + } + var mods = read_name(); + return token("regexp", new RegExp(regexp, mods)); + }); + function read_operator(prefix) { + function grow(op) { + if (!peek()) return op; + var bigger = op + peek(); + if (OPERATORS(bigger)) { + next(); + return grow(bigger); + } else { + return op; + } + } + return token("operator", grow(prefix || next())); + } + function handle_slash() { + next(); + var regex_allowed = S.regex_allowed; + switch (peek()) { + case "/": + S.comments_before.push(read_line_comment()); + S.regex_allowed = regex_allowed; + return next_token(); + + case "*": + S.comments_before.push(read_multiline_comment()); + S.regex_allowed = regex_allowed; + return next_token(); + } + return S.regex_allowed ? read_regexp("") : read_operator("/"); + } + function handle_dot() { + next(); + return is_digit(peek().charCodeAt(0)) ? read_num(".") : token("punc", "."); + } + function read_word() { + var word = read_name(); + return KEYWORDS_ATOM(word) ? token("atom", word) : !KEYWORDS(word) ? token("name", word) : OPERATORS(word) ? token("operator", word) : token("keyword", word); + } + function with_eof_error(eof_error, cont) { + return function(x) { + try { + return cont(x); + } catch (ex) { + if (ex === EX_EOF) parse_error(eof_error); else throw ex; + } + }; + } + function next_token(force_regexp) { + if (force_regexp != null) return read_regexp(force_regexp); + skip_whitespace(); + start_token(); + var ch = peek(); + if (!ch) return token("eof"); + var code = ch.charCodeAt(0); + switch (code) { + case 34: + case 39: + return read_string(); + + case 46: + return handle_dot(); + + case 47: + return handle_slash(); + } + if (is_digit(code)) return read_num(); + if (PUNC_CHARS(ch)) return token("punc", next()); + if (OPERATOR_CHARS(ch)) return read_operator(); + if (code == 92 || is_identifier_start(code)) return read_word(); + parse_error("Unexpected character '" + ch + "'"); + } + next_token.context = function(nc) { + if (nc) S = nc; + return S; + }; + return next_token; + } + var UNARY_PREFIX = makePredicate([ "typeof", "void", "delete", "--", "++", "!", "~", "-", "+" ]); + var UNARY_POSTFIX = makePredicate([ "--", "++" ]); + var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]); + var PRECEDENCE = function(a, ret) { + for (var i = 0, n = 1; i < a.length; ++i, ++n) { + var b = a[i]; + for (var j = 0; j < b.length; ++j) { + ret[b[j]] = n; + } + } + return ret; + }([ [ "||" ], [ "&&" ], [ "|" ], [ "^" ], [ "&" ], [ "==", "===", "!=", "!==" ], [ "<", ">", "<=", ">=", "in", "instanceof" ], [ ">>", "<<", ">>>" ], [ "+", "-" ], [ "*", "/", "%" ] ], {}); + var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); + var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); + function parse($TEXT, options) { + options = defaults(options, { + strict: false, + filename: null, + toplevel: null, + expression: false + }); + var S = { + input: typeof $TEXT == "string" ? tokenizer($TEXT, options.filename) : $TEXT, + token: null, + prev: null, + peeked: null, + in_function: 0, + in_directives: true, + in_loop: 0, + labels: [] + }; + S.token = next(); + function is(type, value) { + return is_token(S.token, type, value); + } + function peek() { + return S.peeked || (S.peeked = S.input()); + } + function next() { + S.prev = S.token; + if (S.peeked) { + S.token = S.peeked; + S.peeked = null; + } else { + S.token = S.input(); + } + S.in_directives = S.in_directives && (S.token.type == "string" || is("punc", ";")); + return S.token; + } + function prev() { + return S.prev; + } + function croak(msg, line, col, pos) { + var ctx = S.input.context(); + js_error(msg, ctx.filename, line != null ? line : ctx.tokline, col != null ? col : ctx.tokcol, pos != null ? pos : ctx.tokpos); + } + function token_error(token, msg) { + croak(msg, token.line, token.col); + } + function unexpected(token) { + if (token == null) token = S.token; + token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); + } + function expect_token(type, val) { + if (is(type, val)) { + return next(); + } + token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»"); + } + function expect(punc) { + return expect_token("punc", punc); + } + function can_insert_semicolon() { + return !options.strict && (S.token.nlb || is("eof") || is("punc", "}")); + } + function semicolon() { + if (is("punc", ";")) next(); else if (!can_insert_semicolon()) unexpected(); + } + function parenthesised() { + expect("("); + var exp = expression(true); + expect(")"); + return exp; + } + function embed_tokens(parser) { + return function() { + var start = S.token; + var expr = parser(); + var end = prev(); + expr.start = start; + expr.end = end; + return expr; + }; + } + var statement = embed_tokens(function() { + var tmp; + if (is("operator", "/") || is("operator", "/=")) { + S.peeked = null; + S.token = S.input(S.token.value.substr(1)); + } + switch (S.token.type) { + case "string": + var dir = S.in_directives, stat = simple_statement(); + if (dir && stat.body instanceof AST_String && !is("punc", ",")) return new AST_Directive({ + value: stat.body.value + }); + return stat; + + case "num": + case "regexp": + case "operator": + case "atom": + return simple_statement(); + + case "name": + return is_token(peek(), "punc", ":") ? labeled_statement() : simple_statement(); + + case "punc": + switch (S.token.value) { + case "{": + return new AST_BlockStatement({ + start: S.token, + body: block_(), + end: prev() + }); + + case "[": + case "(": + return simple_statement(); + + case ";": + next(); + return new AST_EmptyStatement(); + + default: + unexpected(); + } + + case "keyword": + switch (tmp = S.token.value, next(), tmp) { + case "break": + return break_cont(AST_Break); + + case "continue": + return break_cont(AST_Continue); + + case "debugger": + semicolon(); + return new AST_Debugger(); + + case "do": + return new AST_Do({ + body: in_loop(statement), + condition: (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), + tmp) + }); + + case "while": + return new AST_While({ + condition: parenthesised(), + body: in_loop(statement) + }); + + case "for": + return for_(); + + case "function": + return function_(true); + + case "if": + return if_(); + + case "return": + if (S.in_function == 0) croak("'return' outside of function"); + return new AST_Return({ + value: is("punc", ";") ? (next(), null) : can_insert_semicolon() ? null : (tmp = expression(true), + semicolon(), tmp) + }); + + case "switch": + return new AST_Switch({ + expression: parenthesised(), + body: in_loop(switch_body_) + }); + + case "throw": + if (S.token.nlb) croak("Illegal newline after 'throw'"); + return new AST_Throw({ + value: (tmp = expression(true), semicolon(), tmp) + }); + + case "try": + return try_(); + + case "var": + return tmp = var_(), semicolon(), tmp; + + case "const": + return tmp = const_(), semicolon(), tmp; + + case "with": + return new AST_With({ + expression: parenthesised(), + body: statement() + }); + + default: + unexpected(); + } + } + }); + function labeled_statement() { + var label = as_symbol(AST_Label); + if (find_if(function(l) { + return l.name == label.name; + }, S.labels)) { + croak("Label " + label.name + " defined twice"); + } + expect(":"); + S.labels.push(label); + var stat = statement(); + S.labels.pop(); + return new AST_LabeledStatement({ + body: stat, + label: label + }); + } + function simple_statement(tmp) { + return new AST_SimpleStatement({ + body: (tmp = expression(true), semicolon(), tmp) + }); + } + function break_cont(type) { + var label = null; + if (!can_insert_semicolon()) { + label = as_symbol(AST_LabelRef, true); + } + if (label != null) { + if (!find_if(function(l) { + return l.name == label.name; + }, S.labels)) croak("Undefined label " + label.name); + } else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch"); + semicolon(); + return new type({ + label: label + }); + } + function for_() { + expect("("); + var init = null; + if (!is("punc", ";")) { + init = is("keyword", "var") ? (next(), var_(true)) : expression(true, true); + if (is("operator", "in")) { + if (init instanceof AST_Var && init.definitions.length > 1) croak("Only one variable declaration allowed in for..in loop"); + next(); + return for_in(init); + } + } + return regular_for(init); + } + function regular_for(init) { + expect(";"); + var test = is("punc", ";") ? null : expression(true); + expect(";"); + var step = is("punc", ")") ? null : expression(true); + expect(")"); + return new AST_For({ + init: init, + condition: test, + step: step, + body: in_loop(statement) + }); + } + function for_in(init) { + var lhs = init instanceof AST_Var ? init.definitions[0].name : null; + var obj = expression(true); + expect(")"); + return new AST_ForIn({ + init: init, + name: lhs, + object: obj, + body: in_loop(statement) + }); + } + var function_ = function(in_statement, ctor) { + var is_accessor = ctor === AST_Accessor; + var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : is_accessor ? AST_SymbolAccessor : AST_SymbolLambda) : is_accessor && (is("string") || is("num")) ? as_atom_node() : null; + if (in_statement && !name) unexpected(); + expect("("); + if (!ctor) ctor = in_statement ? AST_Defun : AST_Function; + return new ctor({ + name: name, + argnames: function(first, a) { + while (!is("punc", ")")) { + if (first) first = false; else expect(","); + a.push(as_symbol(AST_SymbolFunarg)); + } + next(); + return a; + }(true, []), + body: function(loop, labels) { + ++S.in_function; + S.in_directives = true; + S.in_loop = 0; + S.labels = []; + var a = block_(); + --S.in_function; + S.in_loop = loop; + S.labels = labels; + return a; + }(S.in_loop, S.labels) + }); + }; + function if_() { + var cond = parenthesised(), body = statement(), belse = null; + if (is("keyword", "else")) { + next(); + belse = statement(); + } + return new AST_If({ + condition: cond, + body: body, + alternative: belse + }); + } + function block_() { + expect("{"); + var a = []; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + a.push(statement()); + } + next(); + return a; + } + function switch_body_() { + expect("{"); + var a = [], cur = null, branch = null, tmp; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + if (is("keyword", "case")) { + if (branch) branch.end = prev(); + cur = []; + branch = new AST_Case({ + start: (tmp = S.token, next(), tmp), + expression: expression(true), + body: cur + }); + a.push(branch); + expect(":"); + } else if (is("keyword", "default")) { + if (branch) branch.end = prev(); + cur = []; + branch = new AST_Default({ + start: (tmp = S.token, next(), expect(":"), tmp), + body: cur + }); + a.push(branch); + } else { + if (!cur) unexpected(); + cur.push(statement()); + } + } + if (branch) branch.end = prev(); + next(); + return a; + } + function try_() { + var body = block_(), bcatch = null, bfinally = null; + if (is("keyword", "catch")) { + var start = S.token; + next(); + expect("("); + var name = as_symbol(AST_SymbolCatch); + expect(")"); + bcatch = new AST_Catch({ + start: start, + argname: name, + body: block_(), + end: prev() + }); + } + if (is("keyword", "finally")) { + var start = S.token; + next(); + bfinally = new AST_Finally({ + start: start, + body: block_(), + end: prev() + }); + } + if (!bcatch && !bfinally) croak("Missing catch/finally blocks"); + return new AST_Try({ + body: body, + bcatch: bcatch, + bfinally: bfinally + }); + } + function vardefs(no_in, in_const) { + var a = []; + for (;;) { + a.push(new AST_VarDef({ + start: S.token, + name: as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar), + value: is("operator", "=") ? (next(), expression(false, no_in)) : null, + end: prev() + })); + if (!is("punc", ",")) break; + next(); + } + return a; + } + var var_ = function(no_in) { + return new AST_Var({ + start: prev(), + definitions: vardefs(no_in, false), + end: prev() + }); + }; + var const_ = function() { + return new AST_Const({ + start: prev(), + definitions: vardefs(false, true), + end: prev() + }); + }; + var new_ = function() { + var start = S.token; + expect_token("operator", "new"); + var newexp = expr_atom(false), args; + if (is("punc", "(")) { + next(); + args = expr_list(")"); + } else { + args = []; + } + return subscripts(new AST_New({ + start: start, + expression: newexp, + args: args, + end: prev() + }), true); + }; + function as_atom_node() { + var tok = S.token, ret; + switch (tok.type) { + case "name": + return as_symbol(AST_SymbolRef); + + case "num": + ret = new AST_Number({ + start: tok, + end: tok, + value: tok.value + }); + break; + + case "string": + ret = new AST_String({ + start: tok, + end: tok, + value: tok.value + }); + break; + + case "regexp": + ret = new AST_RegExp({ + start: tok, + end: tok, + value: tok.value + }); + break; + + case "atom": + switch (tok.value) { + case "false": + ret = new AST_False({ + start: tok, + end: tok + }); + break; + + case "true": + ret = new AST_True({ + start: tok, + end: tok + }); + break; + + case "null": + ret = new AST_Null({ + start: tok, + end: tok + }); + break; + } + break; + } + next(); + return ret; + } + var expr_atom = function(allow_calls) { + if (is("operator", "new")) { + return new_(); + } + var start = S.token; + if (is("punc")) { + switch (start.value) { + case "(": + next(); + var ex = expression(true); + ex.start = start; + ex.end = S.token; + expect(")"); + return subscripts(ex, allow_calls); + + case "[": + return subscripts(array_(), allow_calls); + + case "{": + return subscripts(object_(), allow_calls); + } + unexpected(); + } + if (is("keyword", "function")) { + next(); + var func = function_(false); + func.start = start; + func.end = prev(); + return subscripts(func, allow_calls); + } + if (ATOMIC_START_TOKEN[S.token.type]) { + return subscripts(as_atom_node(), allow_calls); + } + unexpected(); + }; + function expr_list(closing, allow_trailing_comma, allow_empty) { + var first = true, a = []; + while (!is("punc", closing)) { + if (first) first = false; else expect(","); + if (allow_trailing_comma && is("punc", closing)) break; + if (is("punc", ",") && allow_empty) { + a.push(new AST_Hole({ + start: S.token, + end: S.token + })); + } else { + a.push(expression(false)); + } + } + next(); + return a; + } + var array_ = embed_tokens(function() { + expect("["); + return new AST_Array({ + elements: expr_list("]", !options.strict, true) + }); + }); + var object_ = embed_tokens(function() { + expect("{"); + var first = true, a = []; + while (!is("punc", "}")) { + if (first) first = false; else expect(","); + if (!options.strict && is("punc", "}")) break; + var start = S.token; + var type = start.type; + var name = as_property_name(); + if (type == "name" && !is("punc", ":")) { + if (name == "get") { + a.push(new AST_ObjectGetter({ + start: start, + key: name, + value: function_(false, AST_Accessor), + end: prev() + })); + continue; + } + if (name == "set") { + a.push(new AST_ObjectSetter({ + start: start, + key: name, + value: function_(false, AST_Accessor), + end: prev() + })); + continue; + } + } + expect(":"); + a.push(new AST_ObjectKeyVal({ + start: start, + key: name, + value: expression(false), + end: prev() + })); + } + next(); + return new AST_Object({ + properties: a + }); + }); + function as_property_name() { + var tmp = S.token; + next(); + switch (tmp.type) { + case "num": + case "string": + case "name": + case "operator": + case "keyword": + case "atom": + return tmp.value; + + default: + unexpected(); + } + } + function as_name() { + var tmp = S.token; + next(); + switch (tmp.type) { + case "name": + case "operator": + case "keyword": + case "atom": + return tmp.value; + + default: + unexpected(); + } + } + function as_symbol(type, noerror) { + if (!is("name")) { + if (!noerror) croak("Name expected"); + return null; + } + var name = S.token.value; + var sym = new (name == "this" ? AST_This : type)({ + name: String(S.token.value), + start: S.token, + end: S.token + }); + next(); + return sym; + } + var subscripts = function(expr, allow_calls) { + var start = expr.start; + if (is("punc", ".")) { + next(); + return subscripts(new AST_Dot({ + start: start, + expression: expr, + property: as_name(), + end: prev() + }), allow_calls); + } + if (is("punc", "[")) { + next(); + var prop = expression(true); + expect("]"); + return subscripts(new AST_Sub({ + start: start, + expression: expr, + property: prop, + end: prev() + }), allow_calls); + } + if (allow_calls && is("punc", "(")) { + next(); + return subscripts(new AST_Call({ + start: start, + expression: expr, + args: expr_list(")"), + end: prev() + }), true); + } + return expr; + }; + var maybe_unary = function(allow_calls) { + var start = S.token; + if (is("operator") && UNARY_PREFIX(start.value)) { + next(); + var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls)); + ex.start = start; + ex.end = prev(); + return ex; + } + var val = expr_atom(allow_calls); + while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) { + val = make_unary(AST_UnaryPostfix, S.token.value, val); + val.start = start; + val.end = S.token; + next(); + } + return val; + }; + function make_unary(ctor, op, expr) { + if ((op == "++" || op == "--") && !is_assignable(expr)) croak("Invalid use of " + op + " operator"); + return new ctor({ + operator: op, + expression: expr + }); + } + var expr_op = function(left, min_prec, no_in) { + var op = is("operator") ? S.token.value : null; + if (op == "in" && no_in) op = null; + var prec = op != null ? PRECEDENCE[op] : null; + if (prec != null && prec > min_prec) { + next(); + var right = expr_op(maybe_unary(true), prec, no_in); + return expr_op(new AST_Binary({ + start: left.start, + left: left, + operator: op, + right: right, + end: right.end + }), min_prec, no_in); + } + return left; + }; + function expr_ops(no_in) { + return expr_op(maybe_unary(true), 0, no_in); + } + var maybe_conditional = function(no_in) { + var start = S.token; + var expr = expr_ops(no_in); + if (is("operator", "?")) { + next(); + var yes = expression(false); + expect(":"); + return new AST_Conditional({ + start: start, + condition: expr, + consequent: yes, + alternative: expression(false, no_in), + end: peek() + }); + } + return expr; + }; + function is_assignable(expr) { + if (!options.strict) return true; + if (expr instanceof AST_This) return false; + return expr instanceof AST_PropAccess || expr instanceof AST_Symbol; + } + var maybe_assign = function(no_in) { + var start = S.token; + var left = maybe_conditional(no_in), val = S.token.value; + if (is("operator") && ASSIGNMENT(val)) { + if (is_assignable(left)) { + next(); + return new AST_Assign({ + start: start, + left: left, + operator: val, + right: maybe_assign(no_in), + end: prev() + }); + } + croak("Invalid assignment"); + } + return left; + }; + var expression = function(commas, no_in) { + var start = S.token; + var expr = maybe_assign(no_in); + if (commas && is("punc", ",")) { + next(); + return new AST_Seq({ + start: start, + car: expr, + cdr: expression(true, no_in), + end: peek() + }); + } + return expr; + }; + function in_loop(cont) { + ++S.in_loop; + var ret = cont(); + --S.in_loop; + return ret; + } + if (options.expression) { + return expression(true); + } + return function() { + var start = S.token; + var body = []; + while (!is("eof")) body.push(statement()); + var end = prev(); + var toplevel = options.toplevel; + if (toplevel) { + toplevel.body = toplevel.body.concat(body); + toplevel.end = end; + } else { + toplevel = new AST_Toplevel({ + start: start, + body: body, + end: end + }); + } + return toplevel; + }(); + } + "use strict"; + function TreeTransformer(before, after) { + TreeWalker.call(this); + this.before = before; + this.after = after; + } + TreeTransformer.prototype = new TreeWalker(); + (function(undefined) { + function _(node, descend) { + node.DEFMETHOD("transform", function(tw, in_list) { + var x, y; + tw.push(this); + if (tw.before) x = tw.before(this, descend, in_list); + if (x === undefined) { + if (!tw.after) { + x = this; + descend(x, tw); + } else { + tw.stack[tw.stack.length - 1] = x = this.clone(); + descend(x, tw); + y = tw.after(x, in_list); + if (y !== undefined) x = y; + } + } + tw.pop(); + return x; + }); + } + function do_list(list, tw) { + return MAP(list, function(node) { + return node.transform(tw, true); + }); + } + _(AST_Node, noop); + _(AST_LabeledStatement, function(self, tw) { + self.label = self.label.transform(tw); + self.body = self.body.transform(tw); + }); + _(AST_SimpleStatement, function(self, tw) { + self.body = self.body.transform(tw); + }); + _(AST_Block, function(self, tw) { + self.body = do_list(self.body, tw); + }); + _(AST_DWLoop, function(self, tw) { + self.condition = self.condition.transform(tw); + self.body = self.body.transform(tw); + }); + _(AST_For, function(self, tw) { + if (self.init) self.init = self.init.transform(tw); + if (self.condition) self.condition = self.condition.transform(tw); + if (self.step) self.step = self.step.transform(tw); + self.body = self.body.transform(tw); + }); + _(AST_ForIn, function(self, tw) { + self.init = self.init.transform(tw); + self.object = self.object.transform(tw); + self.body = self.body.transform(tw); + }); + _(AST_With, function(self, tw) { + self.expression = self.expression.transform(tw); + self.body = self.body.transform(tw); + }); + _(AST_Exit, function(self, tw) { + if (self.value) self.value = self.value.transform(tw); + }); + _(AST_LoopControl, function(self, tw) { + if (self.label) self.label = self.label.transform(tw); + }); + _(AST_If, function(self, tw) { + self.condition = self.condition.transform(tw); + self.body = self.body.transform(tw); + if (self.alternative) self.alternative = self.alternative.transform(tw); + }); + _(AST_Switch, function(self, tw) { + self.expression = self.expression.transform(tw); + self.body = do_list(self.body, tw); + }); + _(AST_Case, function(self, tw) { + self.expression = self.expression.transform(tw); + self.body = do_list(self.body, tw); + }); + _(AST_Try, function(self, tw) { + self.body = do_list(self.body, tw); + if (self.bcatch) self.bcatch = self.bcatch.transform(tw); + if (self.bfinally) self.bfinally = self.bfinally.transform(tw); + }); + _(AST_Catch, function(self, tw) { + self.argname = self.argname.transform(tw); + self.body = do_list(self.body, tw); + }); + _(AST_Definitions, function(self, tw) { + self.definitions = do_list(self.definitions, tw); + }); + _(AST_VarDef, function(self, tw) { + self.name = self.name.transform(tw); + if (self.value) self.value = self.value.transform(tw); + }); + _(AST_Lambda, function(self, tw) { + if (self.name) self.name = self.name.transform(tw); + self.argnames = do_list(self.argnames, tw); + self.body = do_list(self.body, tw); + }); + _(AST_Call, function(self, tw) { + self.expression = self.expression.transform(tw); + self.args = do_list(self.args, tw); + }); + _(AST_Seq, function(self, tw) { + self.car = self.car.transform(tw); + self.cdr = self.cdr.transform(tw); + }); + _(AST_Dot, function(self, tw) { + self.expression = self.expression.transform(tw); + }); + _(AST_Sub, function(self, tw) { + self.expression = self.expression.transform(tw); + self.property = self.property.transform(tw); + }); + _(AST_Unary, function(self, tw) { + self.expression = self.expression.transform(tw); + }); + _(AST_Binary, function(self, tw) { + self.left = self.left.transform(tw); + self.right = self.right.transform(tw); + }); + _(AST_Conditional, function(self, tw) { + self.condition = self.condition.transform(tw); + self.consequent = self.consequent.transform(tw); + self.alternative = self.alternative.transform(tw); + }); + _(AST_Array, function(self, tw) { + self.elements = do_list(self.elements, tw); + }); + _(AST_Object, function(self, tw) { + self.properties = do_list(self.properties, tw); + }); + _(AST_ObjectProperty, function(self, tw) { + self.value = self.value.transform(tw); + }); + })(); + "use strict"; + function SymbolDef(scope, index, orig) { + this.name = orig.name; + this.orig = [ orig ]; + this.scope = scope; + this.references = []; + this.global = false; + this.mangled_name = null; + this.undeclared = false; + this.constant = false; + this.index = index; + } + SymbolDef.prototype = { + unmangleable: function(options) { + return this.global && !(options && options.toplevel) || this.undeclared || !(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with); + }, + mangle: function(options) { + if (!this.mangled_name && !this.unmangleable(options)) { + var s = this.scope; + if (this.orig[0] instanceof AST_SymbolLambda && !options.screw_ie8) s = s.parent_scope; + this.mangled_name = s.next_mangled(options); + } + } + }; + AST_Toplevel.DEFMETHOD("figure_out_scope", function() { + var self = this; + var scope = self.parent_scope = null; + var labels = new Dictionary(); + var nesting = 0; + var tw = new TreeWalker(function(node, descend) { + if (node instanceof AST_Scope) { + node.init_scope_vars(nesting); + var save_scope = node.parent_scope = scope; + var save_labels = labels; + ++nesting; + scope = node; + labels = new Dictionary(); + descend(); + labels = save_labels; + scope = save_scope; + --nesting; + return true; + } + if (node instanceof AST_Directive) { + node.scope = scope; + push_uniq(scope.directives, node.value); + return true; + } + if (node instanceof AST_With) { + for (var s = scope; s; s = s.parent_scope) s.uses_with = true; + return; + } + if (node instanceof AST_LabeledStatement) { + var l = node.label; + if (labels.has(l.name)) throw new Error(string_template("Label {name} defined twice", l)); + labels.set(l.name, l); + descend(); + labels.del(l.name); + return true; + } + if (node instanceof AST_Symbol) { + node.scope = scope; + } + if (node instanceof AST_Label) { + node.thedef = node; + node.init_scope_vars(); + } + if (node instanceof AST_SymbolLambda) { + scope.def_function(node); + } else if (node instanceof AST_SymbolDefun) { + (node.scope = scope.parent_scope).def_function(node); + } else if (node instanceof AST_SymbolVar || node instanceof AST_SymbolConst) { + var def = scope.def_variable(node); + def.constant = node instanceof AST_SymbolConst; + def.init = tw.parent().value; + } else if (node instanceof AST_SymbolCatch) { + scope.def_variable(node); + } + if (node instanceof AST_LabelRef) { + var sym = labels.get(node.name); + if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", { + name: node.name, + line: node.start.line, + col: node.start.col + })); + node.thedef = sym; + } + }); + self.walk(tw); + var func = null; + var globals = self.globals = new Dictionary(); + var tw = new TreeWalker(function(node, descend) { + if (node instanceof AST_Lambda) { + var prev_func = func; + func = node; + descend(); + func = prev_func; + return true; + } + if (node instanceof AST_LabelRef) { + node.reference(); + return true; + } + if (node instanceof AST_SymbolRef) { + var name = node.name; + var sym = node.scope.find_variable(name); + if (!sym) { + var g; + if (globals.has(name)) { + g = globals.get(name); + } else { + g = new SymbolDef(self, globals.size(), node); + g.undeclared = true; + g.global = true; + globals.set(name, g); + } + node.thedef = g; + if (name == "eval" && tw.parent() instanceof AST_Call) { + for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) s.uses_eval = true; + } + if (name == "arguments") { + func.uses_arguments = true; + } + } else { + node.thedef = sym; + } + node.reference(); + return true; + } + }); + self.walk(tw); + }); + AST_Scope.DEFMETHOD("init_scope_vars", function(nesting) { + this.directives = []; + this.variables = new Dictionary(); + this.functions = new Dictionary(); + this.uses_with = false; + this.uses_eval = false; + this.parent_scope = null; + this.enclosed = []; + this.cname = -1; + this.nesting = nesting; + }); + AST_Scope.DEFMETHOD("strict", function() { + return this.has_directive("use strict"); + }); + AST_Lambda.DEFMETHOD("init_scope_vars", function() { + AST_Scope.prototype.init_scope_vars.apply(this, arguments); + this.uses_arguments = false; + }); + AST_SymbolRef.DEFMETHOD("reference", function() { + var def = this.definition(); + def.references.push(this); + var s = this.scope; + while (s) { + push_uniq(s.enclosed, def); + if (s === def.scope) break; + s = s.parent_scope; + } + this.frame = this.scope.nesting - def.scope.nesting; + }); + AST_Label.DEFMETHOD("init_scope_vars", function() { + this.references = []; + }); + AST_LabelRef.DEFMETHOD("reference", function() { + this.thedef.references.push(this); + }); + AST_Scope.DEFMETHOD("find_variable", function(name) { + if (name instanceof AST_Symbol) name = name.name; + return this.variables.get(name) || this.parent_scope && this.parent_scope.find_variable(name); + }); + AST_Scope.DEFMETHOD("has_directive", function(value) { + return this.parent_scope && this.parent_scope.has_directive(value) || (this.directives.indexOf(value) >= 0 ? this : null); + }); + AST_Scope.DEFMETHOD("def_function", function(symbol) { + this.functions.set(symbol.name, this.def_variable(symbol)); + }); + AST_Scope.DEFMETHOD("def_variable", function(symbol) { + var def; + if (!this.variables.has(symbol.name)) { + def = new SymbolDef(this, this.variables.size(), symbol); + this.variables.set(symbol.name, def); + def.global = !this.parent_scope; + } else { + def = this.variables.get(symbol.name); + def.orig.push(symbol); + } + return symbol.thedef = def; + }); + AST_Scope.DEFMETHOD("next_mangled", function(options) { + var ext = this.enclosed; + out: while (true) { + var m = base54(++this.cname); + if (!is_identifier(m)) continue; + for (var i = ext.length; --i >= 0; ) { + var sym = ext[i]; + var name = sym.mangled_name || sym.unmangleable(options) && sym.name; + if (m == name) continue out; + } + return m; + } + }); + AST_Scope.DEFMETHOD("references", function(sym) { + if (sym instanceof AST_Symbol) sym = sym.definition(); + return this.enclosed.indexOf(sym) < 0 ? null : sym; + }); + AST_Symbol.DEFMETHOD("unmangleable", function(options) { + return this.definition().unmangleable(options); + }); + AST_SymbolAccessor.DEFMETHOD("unmangleable", function() { + return true; + }); + AST_Label.DEFMETHOD("unmangleable", function() { + return false; + }); + AST_Symbol.DEFMETHOD("unreferenced", function() { + return this.definition().references.length == 0 && !(this.scope.uses_eval || this.scope.uses_with); + }); + AST_Symbol.DEFMETHOD("undeclared", function() { + return this.definition().undeclared; + }); + AST_LabelRef.DEFMETHOD("undeclared", function() { + return false; + }); + AST_Label.DEFMETHOD("undeclared", function() { + return false; + }); + AST_Symbol.DEFMETHOD("definition", function() { + return this.thedef; + }); + AST_Symbol.DEFMETHOD("global", function() { + return this.definition().global; + }); + AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) { + return defaults(options, { + except: [], + eval: false, + sort: false, + toplevel: false, + screw_ie8: false + }); + }); + AST_Toplevel.DEFMETHOD("mangle_names", function(options) { + options = this._default_mangler_options(options); + var lname = -1; + var to_mangle = []; + var tw = new TreeWalker(function(node, descend) { + if (node instanceof AST_LabeledStatement) { + var save_nesting = lname; + descend(); + lname = save_nesting; + return true; + } + if (node instanceof AST_Scope) { + var p = tw.parent(), a = []; + node.variables.each(function(symbol) { + if (options.except.indexOf(symbol.name) < 0) { + a.push(symbol); + } + }); + if (options.sort) a.sort(function(a, b) { + return b.references.length - a.references.length; + }); + to_mangle.push.apply(to_mangle, a); + return; + } + if (node instanceof AST_Label) { + var name; + do name = base54(++lname); while (!is_identifier(name)); + node.mangled_name = name; + return true; + } + }); + this.walk(tw); + to_mangle.forEach(function(def) { + def.mangle(options); + }); + }); + AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) { + options = this._default_mangler_options(options); + var tw = new TreeWalker(function(node) { + if (node instanceof AST_Constant) base54.consider(node.print_to_string()); else if (node instanceof AST_Return) base54.consider("return"); else if (node instanceof AST_Throw) base54.consider("throw"); else if (node instanceof AST_Continue) base54.consider("continue"); else if (node instanceof AST_Break) base54.consider("break"); else if (node instanceof AST_Debugger) base54.consider("debugger"); else if (node instanceof AST_Directive) base54.consider(node.value); else if (node instanceof AST_While) base54.consider("while"); else if (node instanceof AST_Do) base54.consider("do while"); else if (node instanceof AST_If) { + base54.consider("if"); + if (node.alternative) base54.consider("else"); + } else if (node instanceof AST_Var) base54.consider("var"); else if (node instanceof AST_Const) base54.consider("const"); else if (node instanceof AST_Lambda) base54.consider("function"); else if (node instanceof AST_For) base54.consider("for"); else if (node instanceof AST_ForIn) base54.consider("for in"); else if (node instanceof AST_Switch) base54.consider("switch"); else if (node instanceof AST_Case) base54.consider("case"); else if (node instanceof AST_Default) base54.consider("default"); else if (node instanceof AST_With) base54.consider("with"); else if (node instanceof AST_ObjectSetter) base54.consider("set" + node.key); else if (node instanceof AST_ObjectGetter) base54.consider("get" + node.key); else if (node instanceof AST_ObjectKeyVal) base54.consider(node.key); else if (node instanceof AST_New) base54.consider("new"); else if (node instanceof AST_This) base54.consider("this"); else if (node instanceof AST_Try) base54.consider("try"); else if (node instanceof AST_Catch) base54.consider("catch"); else if (node instanceof AST_Finally) base54.consider("finally"); else if (node instanceof AST_Symbol && node.unmangleable(options)) base54.consider(node.name); else if (node instanceof AST_Unary || node instanceof AST_Binary) base54.consider(node.operator); else if (node instanceof AST_Dot) base54.consider(node.property); + }); + this.walk(tw); + base54.sort(); + }); + var base54 = function() { + var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; + var chars, frequency; + function reset() { + frequency = Object.create(null); + chars = string.split("").map(function(ch) { + return ch.charCodeAt(0); + }); + chars.forEach(function(ch) { + frequency[ch] = 0; + }); + } + base54.consider = function(str) { + for (var i = str.length; --i >= 0; ) { + var code = str.charCodeAt(i); + if (code in frequency) ++frequency[code]; + } + }; + base54.sort = function() { + chars = mergeSort(chars, function(a, b) { + if (is_digit(a) && !is_digit(b)) return 1; + if (is_digit(b) && !is_digit(a)) return -1; + return frequency[b] - frequency[a]; + }); + }; + base54.reset = reset; + reset(); + base54.get = function() { + return chars; + }; + base54.freq = function() { + return frequency; + }; + function base54(num) { + var ret = "", base = 54; + do { + ret += String.fromCharCode(chars[num % base]); + num = Math.floor(num / base); + base = 64; + } while (num > 0); + return ret; + } + return base54; + }(); + AST_Toplevel.DEFMETHOD("scope_warnings", function(options) { + options = defaults(options, { + undeclared: false, + unreferenced: true, + assign_to_global: true, + func_arguments: true, + nested_defuns: true, + eval: true + }); + var tw = new TreeWalker(function(node) { + if (options.undeclared && node instanceof AST_SymbolRef && node.undeclared()) { + AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", { + name: node.name, + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + if (options.assign_to_global) { + var sym = null; + if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) sym = node.left; else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef) sym = node.init; + if (sym && (sym.undeclared() || sym.global() && sym.scope !== sym.definition().scope)) { + AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", { + msg: sym.undeclared() ? "Accidental global?" : "Assignment to global", + name: sym.name, + file: sym.start.file, + line: sym.start.line, + col: sym.start.col + }); + } + } + if (options.eval && node instanceof AST_SymbolRef && node.undeclared() && node.name == "eval") { + AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start); + } + if (options.unreferenced && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) && node.unreferenced()) { + AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", { + type: node instanceof AST_Label ? "Label" : "Symbol", + name: node.name, + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + if (options.func_arguments && node instanceof AST_Lambda && node.uses_arguments) { + AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", { + name: node.name ? node.name.name : "anonymous", + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + if (options.nested_defuns && node instanceof AST_Defun && !(tw.parent() instanceof AST_Scope)) { + AST_Node.warn('Function {name} declared in nested statement "{type}" [{file}:{line},{col}]', { + name: node.name.name, + type: tw.parent().TYPE, + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + }); + this.walk(tw); + }); + "use strict"; + function OutputStream(options) { + options = defaults(options, { + indent_start: 0, + indent_level: 4, + quote_keys: false, + space_colon: true, + ascii_only: false, + inline_script: false, + width: 80, + max_line_len: 32e3, + beautify: false, + source_map: null, + bracketize: false, + semicolons: true, + comments: false, + preserve_line: false, + screw_ie8: false + }, true); + var indentation = 0; + var current_col = 0; + var current_line = 1; + var current_pos = 0; + var OUTPUT = ""; + function to_ascii(str, identifier) { + return str.replace(/[\u0080-\uffff]/g, function(ch) { + var code = ch.charCodeAt(0).toString(16); + if (code.length <= 2 && !identifier) { + while (code.length < 2) code = "0" + code; + return "\\x" + code; + } else { + while (code.length < 4) code = "0" + code; + return "\\u" + code; + } + }); + } + function make_string(str) { + var dq = 0, sq = 0; + str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s) { + switch (s) { + case "\\": + return "\\\\"; + + case "\b": + return "\\b"; + + case "\f": + return "\\f"; + + case "\n": + return "\\n"; + + case "\r": + return "\\r"; + + case "\u2028": + return "\\u2028"; + + case "\u2029": + return "\\u2029"; + + case '"': + ++dq; + return '"'; + + case "'": + ++sq; + return "'"; + + case "\x00": + return "\\x00"; + } + return s; + }); + if (options.ascii_only) str = to_ascii(str); + if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; else return '"' + str.replace(/\x22/g, '\\"') + '"'; + } + function encode_string(str) { + var ret = make_string(str); + if (options.inline_script) ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); + return ret; + } + function make_name(name) { + name = name.toString(); + if (options.ascii_only) name = to_ascii(name, true); + return name; + } + function make_indent(back) { + return repeat_string(" ", options.indent_start + indentation - back * options.indent_level); + } + var might_need_space = false; + var might_need_semicolon = false; + var last = null; + function last_char() { + return last.charAt(last.length - 1); + } + function maybe_newline() { + if (options.max_line_len && current_col > options.max_line_len) print("\n"); + } + var requireSemicolonChars = makePredicate("( [ + * / - , ."); + function print(str) { + str = String(str); + var ch = str.charAt(0); + if (might_need_semicolon) { + if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) { + if (options.semicolons || requireSemicolonChars(ch)) { + OUTPUT += ";"; + current_col++; + current_pos++; + } else { + OUTPUT += "\n"; + current_pos++; + current_line++; + current_col = 0; + } + if (!options.beautify) might_need_space = false; + } + might_need_semicolon = false; + maybe_newline(); + } + if (!options.beautify && options.preserve_line && stack[stack.length - 1]) { + var target_line = stack[stack.length - 1].start.line; + while (current_line < target_line) { + OUTPUT += "\n"; + current_pos++; + current_line++; + current_col = 0; + might_need_space = false; + } + } + if (might_need_space) { + var prev = last_char(); + if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\") || /^[\+\-\/]$/.test(ch) && ch == prev) { + OUTPUT += " "; + current_col++; + current_pos++; + } + might_need_space = false; + } + var a = str.split(/\r?\n/), n = a.length - 1; + current_line += n; + if (n == 0) { + current_col += a[n].length; + } else { + current_col = a[n].length; + } + current_pos += str.length; + last = str; + OUTPUT += str; + } + var space = options.beautify ? function() { + print(" "); + } : function() { + might_need_space = true; + }; + var indent = options.beautify ? function(half) { + if (options.beautify) { + print(make_indent(half ? .5 : 0)); + } + } : noop; + var with_indent = options.beautify ? function(col, cont) { + if (col === true) col = next_indent(); + var save_indentation = indentation; + indentation = col; + var ret = cont(); + indentation = save_indentation; + return ret; + } : function(col, cont) { + return cont(); + }; + var newline = options.beautify ? function() { + print("\n"); + } : noop; + var semicolon = options.beautify ? function() { + print(";"); + } : function() { + might_need_semicolon = true; + }; + function force_semicolon() { + might_need_semicolon = false; + print(";"); + } + function next_indent() { + return indentation + options.indent_level; + } + function with_block(cont) { + var ret; + print("{"); + newline(); + with_indent(next_indent(), function() { + ret = cont(); + }); + indent(); + print("}"); + return ret; + } + function with_parens(cont) { + print("("); + var ret = cont(); + print(")"); + return ret; + } + function with_square(cont) { + print("["); + var ret = cont(); + print("]"); + return ret; + } + function comma() { + print(","); + space(); + } + function colon() { + print(":"); + if (options.space_colon) space(); + } + var add_mapping = options.source_map ? function(token, name) { + try { + if (token) options.source_map.add(token.file || "?", current_line, current_col, token.line, token.col, !name && token.type == "name" ? token.value : name); + } catch (ex) { + AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", { + file: token.file, + line: token.line, + col: token.col, + cline: current_line, + ccol: current_col, + name: name || "" + }); + } + } : noop; + function get() { + return OUTPUT; + } + var stack = []; + return { + get: get, + toString: get, + indent: indent, + indentation: function() { + return indentation; + }, + current_width: function() { + return current_col - indentation; + }, + should_break: function() { + return options.width && this.current_width() >= options.width; + }, + newline: newline, + print: print, + space: space, + comma: comma, + colon: colon, + last: function() { + return last; + }, + semicolon: semicolon, + force_semicolon: force_semicolon, + to_ascii: to_ascii, + print_name: function(name) { + print(make_name(name)); + }, + print_string: function(str) { + print(encode_string(str)); + }, + next_indent: next_indent, + with_indent: with_indent, + with_block: with_block, + with_parens: with_parens, + with_square: with_square, + add_mapping: add_mapping, + option: function(opt) { + return options[opt]; + }, + line: function() { + return current_line; + }, + col: function() { + return current_col; + }, + pos: function() { + return current_pos; + }, + push_node: function(node) { + stack.push(node); + }, + pop_node: function() { + return stack.pop(); + }, + stack: function() { + return stack; + }, + parent: function(n) { + return stack[stack.length - 2 - (n || 0)]; + } + }; + } + (function() { + function DEFPRINT(nodetype, generator) { + nodetype.DEFMETHOD("_codegen", generator); + } + AST_Node.DEFMETHOD("print", function(stream, force_parens) { + var self = this, generator = self._codegen; + function doit() { + self.add_comments(stream); + self.add_source_map(stream); + generator(self, stream); + } + stream.push_node(self); + if (force_parens || self.needs_parens(stream)) { + stream.with_parens(doit); + } else { + doit(); + } + stream.pop_node(); + }); + AST_Node.DEFMETHOD("print_to_string", function(options) { + var s = OutputStream(options); + this.print(s); + return s.get(); + }); + AST_Node.DEFMETHOD("add_comments", function(output) { + var c = output.option("comments"), self = this; + if (c) { + var start = self.start; + if (start && !start._comments_dumped) { + start._comments_dumped = true; + var comments = start.comments_before; + if (self instanceof AST_Exit && self.value && self.value.start.comments_before.length > 0) { + comments = (comments || []).concat(self.value.start.comments_before); + self.value.start.comments_before = []; + } + if (c.test) { + comments = comments.filter(function(comment) { + return c.test(comment.value); + }); + } else if (typeof c == "function") { + comments = comments.filter(function(comment) { + return c(self, comment); + }); + } + comments.forEach(function(c) { + if (c.type == "comment1") { + output.print("//" + c.value + "\n"); + output.indent(); + } else if (c.type == "comment2") { + output.print("/*" + c.value + "*/"); + if (start.nlb) { + output.print("\n"); + output.indent(); + } else { + output.space(); + } + } + }); + } + } + }); + function PARENS(nodetype, func) { + nodetype.DEFMETHOD("needs_parens", func); + } + PARENS(AST_Node, function() { + return false; + }); + PARENS(AST_Function, function(output) { + return first_in_statement(output); + }); + PARENS(AST_Object, function(output) { + return first_in_statement(output); + }); + PARENS(AST_Unary, function(output) { + var p = output.parent(); + return p instanceof AST_PropAccess && p.expression === this; + }); + PARENS(AST_Seq, function(output) { + var p = output.parent(); + return p instanceof AST_Call || p instanceof AST_Unary || p instanceof AST_Binary || p instanceof AST_VarDef || p instanceof AST_Dot || p instanceof AST_Array || p instanceof AST_ObjectProperty || p instanceof AST_Conditional; + }); + PARENS(AST_Binary, function(output) { + var p = output.parent(); + if (p instanceof AST_Call && p.expression === this) return true; + if (p instanceof AST_Unary) return true; + if (p instanceof AST_PropAccess && p.expression === this) return true; + if (p instanceof AST_Binary) { + var po = p.operator, pp = PRECEDENCE[po]; + var so = this.operator, sp = PRECEDENCE[so]; + if (pp > sp || pp == sp && this === p.right && !(so == po && (so == "*" || so == "&&" || so == "||"))) { + return true; + } + } + }); + PARENS(AST_PropAccess, function(output) { + var p = output.parent(); + if (p instanceof AST_New && p.expression === this) { + try { + this.walk(new TreeWalker(function(node) { + if (node instanceof AST_Call) throw p; + })); + } catch (ex) { + if (ex !== p) throw ex; + return true; + } + } + }); + PARENS(AST_Call, function(output) { + var p = output.parent(); + return p instanceof AST_New && p.expression === this; + }); + PARENS(AST_New, function(output) { + var p = output.parent(); + if (no_constructor_parens(this, output) && (p instanceof AST_PropAccess || p instanceof AST_Call && p.expression === this)) return true; + }); + PARENS(AST_Number, function(output) { + var p = output.parent(); + if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this) return true; + }); + PARENS(AST_NaN, function(output) { + var p = output.parent(); + if (p instanceof AST_PropAccess && p.expression === this) return true; + }); + function assign_and_conditional_paren_rules(output) { + var p = output.parent(); + if (p instanceof AST_Unary) return true; + if (p instanceof AST_Binary && !(p instanceof AST_Assign)) return true; + if (p instanceof AST_Call && p.expression === this) return true; + if (p instanceof AST_Conditional && p.condition === this) return true; + if (p instanceof AST_PropAccess && p.expression === this) return true; + } + PARENS(AST_Assign, assign_and_conditional_paren_rules); + PARENS(AST_Conditional, assign_and_conditional_paren_rules); + DEFPRINT(AST_Directive, function(self, output) { + output.print_string(self.value); + output.semicolon(); + }); + DEFPRINT(AST_Debugger, function(self, output) { + output.print("debugger"); + output.semicolon(); + }); + function display_body(body, is_toplevel, output) { + var last = body.length - 1; + body.forEach(function(stmt, i) { + if (!(stmt instanceof AST_EmptyStatement)) { + output.indent(); + stmt.print(output); + if (!(i == last && is_toplevel)) { + output.newline(); + if (is_toplevel) output.newline(); + } + } + }); + } + AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) { + force_statement(this.body, output); + }); + DEFPRINT(AST_Statement, function(self, output) { + self.body.print(output); + output.semicolon(); + }); + DEFPRINT(AST_Toplevel, function(self, output) { + display_body(self.body, true, output); + output.print(""); + }); + DEFPRINT(AST_LabeledStatement, function(self, output) { + self.label.print(output); + output.colon(); + self.body.print(output); + }); + DEFPRINT(AST_SimpleStatement, function(self, output) { + self.body.print(output); + output.semicolon(); + }); + function print_bracketed(body, output) { + if (body.length > 0) output.with_block(function() { + display_body(body, false, output); + }); else output.print("{}"); + } + DEFPRINT(AST_BlockStatement, function(self, output) { + print_bracketed(self.body, output); + }); + DEFPRINT(AST_EmptyStatement, function(self, output) { + output.semicolon(); + }); + DEFPRINT(AST_Do, function(self, output) { + output.print("do"); + output.space(); + self._do_print_body(output); + output.space(); + output.print("while"); + output.space(); + output.with_parens(function() { + self.condition.print(output); + }); + output.semicolon(); + }); + DEFPRINT(AST_While, function(self, output) { + output.print("while"); + output.space(); + output.with_parens(function() { + self.condition.print(output); + }); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_For, function(self, output) { + output.print("for"); + output.space(); + output.with_parens(function() { + if (self.init) { + if (self.init instanceof AST_Definitions) { + self.init.print(output); + } else { + parenthesize_for_noin(self.init, output, true); + } + output.print(";"); + output.space(); + } else { + output.print(";"); + } + if (self.condition) { + self.condition.print(output); + output.print(";"); + output.space(); + } else { + output.print(";"); + } + if (self.step) { + self.step.print(output); + } + }); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_ForIn, function(self, output) { + output.print("for"); + output.space(); + output.with_parens(function() { + self.init.print(output); + output.space(); + output.print("in"); + output.space(); + self.object.print(output); + }); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_With, function(self, output) { + output.print("with"); + output.space(); + output.with_parens(function() { + self.expression.print(output); + }); + output.space(); + self._do_print_body(output); + }); + AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) { + var self = this; + if (!nokeyword) { + output.print("function"); + } + if (self.name) { + output.space(); + self.name.print(output); + } + output.with_parens(function() { + self.argnames.forEach(function(arg, i) { + if (i) output.comma(); + arg.print(output); + }); + }); + output.space(); + print_bracketed(self.body, output); + }); + DEFPRINT(AST_Lambda, function(self, output) { + self._do_print(output); + }); + AST_Exit.DEFMETHOD("_do_print", function(output, kind) { + output.print(kind); + if (this.value) { + output.space(); + this.value.print(output); + } + output.semicolon(); + }); + DEFPRINT(AST_Return, function(self, output) { + self._do_print(output, "return"); + }); + DEFPRINT(AST_Throw, function(self, output) { + self._do_print(output, "throw"); + }); + AST_LoopControl.DEFMETHOD("_do_print", function(output, kind) { + output.print(kind); + if (this.label) { + output.space(); + this.label.print(output); + } + output.semicolon(); + }); + DEFPRINT(AST_Break, function(self, output) { + self._do_print(output, "break"); + }); + DEFPRINT(AST_Continue, function(self, output) { + self._do_print(output, "continue"); + }); + function make_then(self, output) { + if (output.option("bracketize")) { + make_block(self.body, output); + return; + } + if (!self.body) return output.force_semicolon(); + if (self.body instanceof AST_Do && !output.option("screw_ie8")) { + make_block(self.body, output); + return; + } + var b = self.body; + while (true) { + if (b instanceof AST_If) { + if (!b.alternative) { + make_block(self.body, output); + return; + } + b = b.alternative; + } else if (b instanceof AST_StatementWithBody) { + b = b.body; + } else break; + } + force_statement(self.body, output); + } + DEFPRINT(AST_If, function(self, output) { + output.print("if"); + output.space(); + output.with_parens(function() { + self.condition.print(output); + }); + output.space(); + if (self.alternative) { + make_then(self, output); + output.space(); + output.print("else"); + output.space(); + force_statement(self.alternative, output); + } else { + self._do_print_body(output); + } + }); + DEFPRINT(AST_Switch, function(self, output) { + output.print("switch"); + output.space(); + output.with_parens(function() { + self.expression.print(output); + }); + output.space(); + if (self.body.length > 0) output.with_block(function() { + self.body.forEach(function(stmt, i) { + if (i) output.newline(); + output.indent(true); + stmt.print(output); + }); + }); else output.print("{}"); + }); + AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) { + if (this.body.length > 0) { + output.newline(); + this.body.forEach(function(stmt) { + output.indent(); + stmt.print(output); + output.newline(); + }); + } + }); + DEFPRINT(AST_Default, function(self, output) { + output.print("default:"); + self._do_print_body(output); + }); + DEFPRINT(AST_Case, function(self, output) { + output.print("case"); + output.space(); + self.expression.print(output); + output.print(":"); + self._do_print_body(output); + }); + DEFPRINT(AST_Try, function(self, output) { + output.print("try"); + output.space(); + print_bracketed(self.body, output); + if (self.bcatch) { + output.space(); + self.bcatch.print(output); + } + if (self.bfinally) { + output.space(); + self.bfinally.print(output); + } + }); + DEFPRINT(AST_Catch, function(self, output) { + output.print("catch"); + output.space(); + output.with_parens(function() { + self.argname.print(output); + }); + output.space(); + print_bracketed(self.body, output); + }); + DEFPRINT(AST_Finally, function(self, output) { + output.print("finally"); + output.space(); + print_bracketed(self.body, output); + }); + AST_Definitions.DEFMETHOD("_do_print", function(output, kind) { + output.print(kind); + output.space(); + this.definitions.forEach(function(def, i) { + if (i) output.comma(); + def.print(output); + }); + var p = output.parent(); + var in_for = p instanceof AST_For || p instanceof AST_ForIn; + var avoid_semicolon = in_for && p.init === this; + if (!avoid_semicolon) output.semicolon(); + }); + DEFPRINT(AST_Var, function(self, output) { + self._do_print(output, "var"); + }); + DEFPRINT(AST_Const, function(self, output) { + self._do_print(output, "const"); + }); + function parenthesize_for_noin(node, output, noin) { + if (!noin) node.print(output); else try { + node.walk(new TreeWalker(function(node) { + if (node instanceof AST_Binary && node.operator == "in") throw output; + })); + node.print(output); + } catch (ex) { + if (ex !== output) throw ex; + node.print(output, true); + } + } + DEFPRINT(AST_VarDef, function(self, output) { + self.name.print(output); + if (self.value) { + output.space(); + output.print("="); + output.space(); + var p = output.parent(1); + var noin = p instanceof AST_For || p instanceof AST_ForIn; + parenthesize_for_noin(self.value, output, noin); + } + }); + DEFPRINT(AST_Call, function(self, output) { + self.expression.print(output); + if (self instanceof AST_New && no_constructor_parens(self, output)) return; + output.with_parens(function() { + self.args.forEach(function(expr, i) { + if (i) output.comma(); + expr.print(output); + }); + }); + }); + DEFPRINT(AST_New, function(self, output) { + output.print("new"); + output.space(); + AST_Call.prototype._codegen(self, output); + }); + AST_Seq.DEFMETHOD("_do_print", function(output) { + this.car.print(output); + if (this.cdr) { + output.comma(); + if (output.should_break()) { + output.newline(); + output.indent(); + } + this.cdr.print(output); + } + }); + DEFPRINT(AST_Seq, function(self, output) { + self._do_print(output); + }); + DEFPRINT(AST_Dot, function(self, output) { + var expr = self.expression; + expr.print(output); + if (expr instanceof AST_Number && expr.getValue() >= 0) { + if (!/[xa-f.]/i.test(output.last())) { + output.print("."); + } + } + output.print("."); + output.add_mapping(self.end); + output.print_name(self.property); + }); + DEFPRINT(AST_Sub, function(self, output) { + self.expression.print(output); + output.print("["); + self.property.print(output); + output.print("]"); + }); + DEFPRINT(AST_UnaryPrefix, function(self, output) { + var op = self.operator; + output.print(op); + if (/^[a-z]/i.test(op)) output.space(); + self.expression.print(output); + }); + DEFPRINT(AST_UnaryPostfix, function(self, output) { + self.expression.print(output); + output.print(self.operator); + }); + DEFPRINT(AST_Binary, function(self, output) { + self.left.print(output); + output.space(); + output.print(self.operator); + output.space(); + self.right.print(output); + }); + DEFPRINT(AST_Conditional, function(self, output) { + self.condition.print(output); + output.space(); + output.print("?"); + output.space(); + self.consequent.print(output); + output.space(); + output.colon(); + self.alternative.print(output); + }); + DEFPRINT(AST_Array, function(self, output) { + output.with_square(function() { + var a = self.elements, len = a.length; + if (len > 0) output.space(); + a.forEach(function(exp, i) { + if (i) output.comma(); + exp.print(output); + if (i === len - 1 && exp instanceof AST_Hole) output.comma(); + }); + if (len > 0) output.space(); + }); + }); + DEFPRINT(AST_Object, function(self, output) { + if (self.properties.length > 0) output.with_block(function() { + self.properties.forEach(function(prop, i) { + if (i) { + output.print(","); + output.newline(); + } + output.indent(); + prop.print(output); + }); + output.newline(); + }); else output.print("{}"); + }); + DEFPRINT(AST_ObjectKeyVal, function(self, output) { + var key = self.key; + if (output.option("quote_keys")) { + output.print_string(key + ""); + } else if ((typeof key == "number" || !output.option("beautify") && +key + "" == key) && parseFloat(key) >= 0) { + output.print(make_num(key)); + } else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) { + output.print_name(key); + } else { + output.print_string(key); + } + output.colon(); + self.value.print(output); + }); + DEFPRINT(AST_ObjectSetter, function(self, output) { + output.print("set"); + self.value._do_print(output, true); + }); + DEFPRINT(AST_ObjectGetter, function(self, output) { + output.print("get"); + self.value._do_print(output, true); + }); + DEFPRINT(AST_Symbol, function(self, output) { + var def = self.definition(); + output.print_name(def ? def.mangled_name || def.name : self.name); + }); + DEFPRINT(AST_Undefined, function(self, output) { + output.print("void 0"); + }); + DEFPRINT(AST_Hole, noop); + DEFPRINT(AST_Infinity, function(self, output) { + output.print("1/0"); + }); + DEFPRINT(AST_NaN, function(self, output) { + output.print("0/0"); + }); + DEFPRINT(AST_This, function(self, output) { + output.print("this"); + }); + DEFPRINT(AST_Constant, function(self, output) { + output.print(self.getValue()); + }); + DEFPRINT(AST_String, function(self, output) { + output.print_string(self.getValue()); + }); + DEFPRINT(AST_Number, function(self, output) { + output.print(make_num(self.getValue())); + }); + DEFPRINT(AST_RegExp, function(self, output) { + var str = self.getValue().toString(); + if (output.option("ascii_only")) str = output.to_ascii(str); + output.print(str); + var p = output.parent(); + if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self) output.print(" "); + }); + function force_statement(stat, output) { + if (output.option("bracketize")) { + if (!stat || stat instanceof AST_EmptyStatement) output.print("{}"); else if (stat instanceof AST_BlockStatement) stat.print(output); else output.with_block(function() { + output.indent(); + stat.print(output); + output.newline(); + }); + } else { + if (!stat || stat instanceof AST_EmptyStatement) output.force_semicolon(); else stat.print(output); + } + } + function first_in_statement(output) { + var a = output.stack(), i = a.length, node = a[--i], p = a[--i]; + while (i > 0) { + if (p instanceof AST_Statement && p.body === node) return true; + if (p instanceof AST_Seq && p.car === node || p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) || p instanceof AST_Dot && p.expression === node || p instanceof AST_Sub && p.expression === node || p instanceof AST_Conditional && p.condition === node || p instanceof AST_Binary && p.left === node || p instanceof AST_UnaryPostfix && p.expression === node) { + node = p; + p = a[--i]; + } else { + return false; + } + } + } + function no_constructor_parens(self, output) { + return self.args.length == 0 && !output.option("beautify"); + } + function best_of(a) { + var best = a[0], len = best.length; + for (var i = 1; i < a.length; ++i) { + if (a[i].length < len) { + best = a[i]; + len = best.length; + } + } + return best; + } + function make_num(num) { + var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace("e+", "e") ], m; + if (Math.floor(num) === num) { + if (num >= 0) { + a.push("0x" + num.toString(16).toLowerCase(), "0" + num.toString(8)); + } else { + a.push("-0x" + (-num).toString(16).toLowerCase(), "-0" + (-num).toString(8)); + } + if (m = /^(.*?)(0+)$/.exec(num)) { + a.push(m[1] + "e" + m[2].length); + } + } else if (m = /^0?\.(0+)(.*)$/.exec(num)) { + a.push(m[2] + "e-" + (m[1].length + m[2].length), str.substr(str.indexOf("."))); + } + return best_of(a); + } + function make_block(stmt, output) { + if (stmt instanceof AST_BlockStatement) { + stmt.print(output); + return; + } + output.with_block(function() { + output.indent(); + stmt.print(output); + output.newline(); + }); + } + function DEFMAP(nodetype, generator) { + nodetype.DEFMETHOD("add_source_map", function(stream) { + generator(this, stream); + }); + } + DEFMAP(AST_Node, noop); + function basic_sourcemap_gen(self, output) { + output.add_mapping(self.start); + } + DEFMAP(AST_Directive, basic_sourcemap_gen); + DEFMAP(AST_Debugger, basic_sourcemap_gen); + DEFMAP(AST_Symbol, basic_sourcemap_gen); + DEFMAP(AST_Jump, basic_sourcemap_gen); + DEFMAP(AST_StatementWithBody, basic_sourcemap_gen); + DEFMAP(AST_LabeledStatement, noop); + DEFMAP(AST_Lambda, basic_sourcemap_gen); + DEFMAP(AST_Switch, basic_sourcemap_gen); + DEFMAP(AST_SwitchBranch, basic_sourcemap_gen); + DEFMAP(AST_BlockStatement, basic_sourcemap_gen); + DEFMAP(AST_Toplevel, noop); + DEFMAP(AST_New, basic_sourcemap_gen); + DEFMAP(AST_Try, basic_sourcemap_gen); + DEFMAP(AST_Catch, basic_sourcemap_gen); + DEFMAP(AST_Finally, basic_sourcemap_gen); + DEFMAP(AST_Definitions, basic_sourcemap_gen); + DEFMAP(AST_Constant, basic_sourcemap_gen); + DEFMAP(AST_ObjectProperty, function(self, output) { + output.add_mapping(self.start, self.key); + }); + })(); + "use strict"; + function Compressor(options, false_by_default) { + if (!(this instanceof Compressor)) return new Compressor(options, false_by_default); + TreeTransformer.call(this, this.before, this.after); + this.options = defaults(options, { + sequences: !false_by_default, + properties: !false_by_default, + dead_code: !false_by_default, + drop_debugger: !false_by_default, + unsafe: false, + unsafe_comps: false, + conditionals: !false_by_default, + comparisons: !false_by_default, + evaluate: !false_by_default, + booleans: !false_by_default, + loops: !false_by_default, + unused: !false_by_default, + hoist_funs: !false_by_default, + hoist_vars: false, + if_return: !false_by_default, + join_vars: !false_by_default, + cascade: !false_by_default, + side_effects: !false_by_default, + negate_iife: !false_by_default, + screw_ie8: false, + warnings: true, + global_defs: {} + }, true); + } + Compressor.prototype = new TreeTransformer(); + merge(Compressor.prototype, { + option: function(key) { + return this.options[key]; + }, + warn: function() { + if (this.options.warnings) AST_Node.warn.apply(AST_Node, arguments); + }, + before: function(node, descend, in_list) { + if (node._squeezed) return node; + if (node instanceof AST_Scope) { + node.drop_unused(this); + node = node.hoist_declarations(this); + } + descend(node, this); + node = node.optimize(this); + if (node instanceof AST_Scope) { + var save_warnings = this.options.warnings; + this.options.warnings = false; + node.drop_unused(this); + this.options.warnings = save_warnings; + } + node._squeezed = true; + return node; + } + }); + (function() { + function OPT(node, optimizer) { + node.DEFMETHOD("optimize", function(compressor) { + var self = this; + if (self._optimized) return self; + var opt = optimizer(self, compressor); + opt._optimized = true; + if (opt === self) return opt; + return opt.transform(compressor); + }); + } + OPT(AST_Node, function(self, compressor) { + return self; + }); + AST_Node.DEFMETHOD("equivalent_to", function(node) { + return this.print_to_string() == node.print_to_string(); + }); + function make_node(ctor, orig, props) { + if (!props) props = {}; + if (orig) { + if (!props.start) props.start = orig.start; + if (!props.end) props.end = orig.end; + } + return new ctor(props); + } + function make_node_from_constant(compressor, val, orig) { + if (val instanceof AST_Node) return val.transform(compressor); + switch (typeof val) { + case "string": + return make_node(AST_String, orig, { + value: val + }).optimize(compressor); + + case "number": + return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, { + value: val + }).optimize(compressor); + + case "boolean": + return make_node(val ? AST_True : AST_False, orig).optimize(compressor); + + case "undefined": + return make_node(AST_Undefined, orig).optimize(compressor); + + default: + if (val === null) { + return make_node(AST_Null, orig).optimize(compressor); + } + if (val instanceof RegExp) { + return make_node(AST_RegExp, orig).optimize(compressor); + } + throw new Error(string_template("Can't handle constant of type: {type}", { + type: typeof val + })); + } + } + function as_statement_array(thing) { + if (thing === null) return []; + if (thing instanceof AST_BlockStatement) return thing.body; + if (thing instanceof AST_EmptyStatement) return []; + if (thing instanceof AST_Statement) return [ thing ]; + throw new Error("Can't convert thing to statement array"); + } + function is_empty(thing) { + if (thing === null) return true; + if (thing instanceof AST_EmptyStatement) return true; + if (thing instanceof AST_BlockStatement) return thing.body.length == 0; + return false; + } + function loop_body(x) { + if (x instanceof AST_Switch) return x; + if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) { + return x.body instanceof AST_BlockStatement ? x.body : x; + } + return x; + } + function tighten_body(statements, compressor) { + var CHANGED; + do { + CHANGED = false; + statements = eliminate_spurious_blocks(statements); + if (compressor.option("dead_code")) { + statements = eliminate_dead_code(statements, compressor); + } + if (compressor.option("if_return")) { + statements = handle_if_return(statements, compressor); + } + if (compressor.option("sequences")) { + statements = sequencesize(statements, compressor); + } + if (compressor.option("join_vars")) { + statements = join_consecutive_vars(statements, compressor); + } + } while (CHANGED); + if (compressor.option("negate_iife")) { + negate_iifes(statements, compressor); + } + return statements; + function eliminate_spurious_blocks(statements) { + var seen_dirs = []; + return statements.reduce(function(a, stat) { + if (stat instanceof AST_BlockStatement) { + CHANGED = true; + a.push.apply(a, eliminate_spurious_blocks(stat.body)); + } else if (stat instanceof AST_EmptyStatement) { + CHANGED = true; + } else if (stat instanceof AST_Directive) { + if (seen_dirs.indexOf(stat.value) < 0) { + a.push(stat); + seen_dirs.push(stat.value); + } else { + CHANGED = true; + } + } else { + a.push(stat); + } + return a; + }, []); + } + function handle_if_return(statements, compressor) { + var self = compressor.self(); + var in_lambda = self instanceof AST_Lambda; + var ret = []; + loop: for (var i = statements.length; --i >= 0; ) { + var stat = statements[i]; + switch (true) { + case in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0: + CHANGED = true; + continue loop; + + case stat instanceof AST_If: + if (stat.body instanceof AST_Return) { + if ((in_lambda && ret.length == 0 || ret[0] instanceof AST_Return && !ret[0].value) && !stat.body.value && !stat.alternative) { + CHANGED = true; + var cond = make_node(AST_SimpleStatement, stat.condition, { + body: stat.condition + }); + ret.unshift(cond); + continue loop; + } + if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) { + CHANGED = true; + stat = stat.clone(); + stat.alternative = ret[0]; + ret[0] = stat.transform(compressor); + continue loop; + } + if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) { + CHANGED = true; + stat = stat.clone(); + stat.alternative = ret[0] || make_node(AST_Return, stat, { + value: make_node(AST_Undefined, stat) + }); + ret[0] = stat.transform(compressor); + continue loop; + } + if (!stat.body.value && in_lambda) { + CHANGED = true; + stat = stat.clone(); + stat.condition = stat.condition.negate(compressor); + stat.body = make_node(AST_BlockStatement, stat, { + body: as_statement_array(stat.alternative).concat(ret) + }); + stat.alternative = null; + ret = [ stat.transform(compressor) ]; + continue loop; + } + if (ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement && (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) { + CHANGED = true; + ret.push(make_node(AST_Return, ret[0], { + value: make_node(AST_Undefined, ret[0]) + }).transform(compressor)); + ret = as_statement_array(stat.alternative).concat(ret); + ret.unshift(stat); + continue loop; + } + } + var ab = aborts(stat.body); + var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null; + if (ab && (ab instanceof AST_Return && !ab.value && in_lambda || ab instanceof AST_Continue && self === loop_body(lct) || ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct)) { + if (ab.label) { + remove(ab.label.thedef.references, ab.label); + } + CHANGED = true; + var body = as_statement_array(stat.body).slice(0, -1); + stat = stat.clone(); + stat.condition = stat.condition.negate(compressor); + stat.body = make_node(AST_BlockStatement, stat, { + body: ret + }); + stat.alternative = make_node(AST_BlockStatement, stat, { + body: body + }); + ret = [ stat.transform(compressor) ]; + continue loop; + } + var ab = aborts(stat.alternative); + var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null; + if (ab && (ab instanceof AST_Return && !ab.value && in_lambda || ab instanceof AST_Continue && self === loop_body(lct) || ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct)) { + if (ab.label) { + remove(ab.label.thedef.references, ab.label); + } + CHANGED = true; + stat = stat.clone(); + stat.body = make_node(AST_BlockStatement, stat.body, { + body: as_statement_array(stat.body).concat(ret) + }); + stat.alternative = make_node(AST_BlockStatement, stat.alternative, { + body: as_statement_array(stat.alternative).slice(0, -1) + }); + ret = [ stat.transform(compressor) ]; + continue loop; + } + ret.unshift(stat); + break; + + default: + ret.unshift(stat); + break; + } + } + return ret; + } + function eliminate_dead_code(statements, compressor) { + var has_quit = false; + var orig = statements.length; + var self = compressor.self(); + statements = statements.reduce(function(a, stat) { + if (has_quit) { + extract_declarations_from_unreachable_code(compressor, stat, a); + } else { + if (stat instanceof AST_LoopControl) { + var lct = compressor.loopcontrol_target(stat.label); + if (stat instanceof AST_Break && lct instanceof AST_BlockStatement && loop_body(lct) === self || stat instanceof AST_Continue && loop_body(lct) === self) { + if (stat.label) { + remove(stat.label.thedef.references, stat.label); + } + } else { + a.push(stat); + } + } else { + a.push(stat); + } + if (aborts(stat)) has_quit = true; + } + return a; + }, []); + CHANGED = statements.length != orig; + return statements; + } + function sequencesize(statements, compressor) { + if (statements.length < 2) return statements; + var seq = [], ret = []; + function push_seq() { + seq = AST_Seq.from_array(seq); + if (seq) ret.push(make_node(AST_SimpleStatement, seq, { + body: seq + })); + seq = []; + } + statements.forEach(function(stat) { + if (stat instanceof AST_SimpleStatement) seq.push(stat.body); else push_seq(), ret.push(stat); + }); + push_seq(); + ret = sequencesize_2(ret, compressor); + CHANGED = ret.length != statements.length; + return ret; + } + function sequencesize_2(statements, compressor) { + function cons_seq(right) { + ret.pop(); + var left = prev.body; + if (left instanceof AST_Seq) { + left.add(right); + } else { + left = AST_Seq.cons(left, right); + } + return left.transform(compressor); + } + var ret = [], prev = null; + statements.forEach(function(stat) { + if (prev) { + if (stat instanceof AST_For) { + var opera = {}; + try { + prev.body.walk(new TreeWalker(function(node) { + if (node instanceof AST_Binary && node.operator == "in") throw opera; + })); + if (stat.init && !(stat.init instanceof AST_Definitions)) { + stat.init = cons_seq(stat.init); + } else if (!stat.init) { + stat.init = prev.body; + ret.pop(); + } + } catch (ex) { + if (ex !== opera) throw ex; + } + } else if (stat instanceof AST_If) { + stat.condition = cons_seq(stat.condition); + } else if (stat instanceof AST_With) { + stat.expression = cons_seq(stat.expression); + } else if (stat instanceof AST_Exit && stat.value) { + stat.value = cons_seq(stat.value); + } else if (stat instanceof AST_Exit) { + stat.value = cons_seq(make_node(AST_Undefined, stat)); + } else if (stat instanceof AST_Switch) { + stat.expression = cons_seq(stat.expression); + } + } + ret.push(stat); + prev = stat instanceof AST_SimpleStatement ? stat : null; + }); + return ret; + } + function join_consecutive_vars(statements, compressor) { + var prev = null; + return statements.reduce(function(a, stat) { + if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) { + prev.definitions = prev.definitions.concat(stat.definitions); + CHANGED = true; + } else if (stat instanceof AST_For && prev instanceof AST_Definitions && (!stat.init || stat.init.TYPE == prev.TYPE)) { + CHANGED = true; + a.pop(); + if (stat.init) { + stat.init.definitions = prev.definitions.concat(stat.init.definitions); + } else { + stat.init = prev; + } + a.push(stat); + prev = stat; + } else { + prev = stat; + a.push(stat); + } + return a; + }, []); + } + function negate_iifes(statements, compressor) { + statements.forEach(function(stat) { + if (stat instanceof AST_SimpleStatement) { + stat.body = function transform(thing) { + return thing.transform(new TreeTransformer(function(node) { + if (node instanceof AST_Call && node.expression instanceof AST_Function) { + return make_node(AST_UnaryPrefix, node, { + operator: "!", + expression: node + }); + } else if (node instanceof AST_Call) { + node.expression = transform(node.expression); + } else if (node instanceof AST_Seq) { + node.car = transform(node.car); + } else if (node instanceof AST_Conditional) { + var expr = transform(node.condition); + if (expr !== node.condition) { + node.condition = expr; + var tmp = node.consequent; + node.consequent = node.alternative; + node.alternative = tmp; + } + } + return node; + })); + }(stat.body); + } + }); + } + } + function extract_declarations_from_unreachable_code(compressor, stat, target) { + compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start); + stat.walk(new TreeWalker(function(node) { + if (node instanceof AST_Definitions) { + compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start); + node.remove_initializers(); + target.push(node); + return true; + } + if (node instanceof AST_Defun) { + target.push(node); + return true; + } + if (node instanceof AST_Scope) { + return true; + } + })); + } + (function(def) { + var unary_bool = [ "!", "delete" ]; + var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ]; + def(AST_Node, function() { + return false; + }); + def(AST_UnaryPrefix, function() { + return member(this.operator, unary_bool); + }); + def(AST_Binary, function() { + return member(this.operator, binary_bool) || (this.operator == "&&" || this.operator == "||") && this.left.is_boolean() && this.right.is_boolean(); + }); + def(AST_Conditional, function() { + return this.consequent.is_boolean() && this.alternative.is_boolean(); + }); + def(AST_Assign, function() { + return this.operator == "=" && this.right.is_boolean(); + }); + def(AST_Seq, function() { + return this.cdr.is_boolean(); + }); + def(AST_True, function() { + return true; + }); + def(AST_False, function() { + return true; + }); + })(function(node, func) { + node.DEFMETHOD("is_boolean", func); + }); + (function(def) { + def(AST_Node, function() { + return false; + }); + def(AST_String, function() { + return true; + }); + def(AST_UnaryPrefix, function() { + return this.operator == "typeof"; + }); + def(AST_Binary, function(compressor) { + return this.operator == "+" && (this.left.is_string(compressor) || this.right.is_string(compressor)); + }); + def(AST_Assign, function(compressor) { + return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor); + }); + def(AST_Seq, function(compressor) { + return this.cdr.is_string(compressor); + }); + def(AST_Conditional, function(compressor) { + return this.consequent.is_string(compressor) && this.alternative.is_string(compressor); + }); + def(AST_Call, function(compressor) { + return compressor.option("unsafe") && this.expression instanceof AST_SymbolRef && this.expression.name == "String" && this.expression.undeclared(); + }); + })(function(node, func) { + node.DEFMETHOD("is_string", func); + }); + function best_of(ast1, ast2) { + return ast1.print_to_string().length > ast2.print_to_string().length ? ast2 : ast1; + } + (function(def) { + AST_Node.DEFMETHOD("evaluate", function(compressor) { + if (!compressor.option("evaluate")) return [ this ]; + try { + var val = this._eval(), ast = make_node_from_constant(compressor, val, this); + return [ best_of(ast, this), val ]; + } catch (ex) { + if (ex !== def) throw ex; + return [ this ]; + } + }); + def(AST_Statement, function() { + throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start)); + }); + def(AST_Function, function() { + throw def; + }); + function ev(node) { + return node._eval(); + } + def(AST_Node, function() { + throw def; + }); + def(AST_Constant, function() { + return this.getValue(); + }); + def(AST_UnaryPrefix, function() { + var e = this.expression; + switch (this.operator) { + case "!": + return !ev(e); + + case "typeof": + if (e instanceof AST_Function) return typeof function() {}; + e = ev(e); + if (e instanceof RegExp) throw def; + return typeof e; + + case "void": + return void ev(e); + + case "~": + return ~ev(e); + + case "-": + e = ev(e); + if (e === 0) throw def; + return -e; + + case "+": + return +ev(e); + } + throw def; + }); + def(AST_Binary, function() { + var left = this.left, right = this.right; + switch (this.operator) { + case "&&": + return ev(left) && ev(right); + + case "||": + return ev(left) || ev(right); + + case "|": + return ev(left) | ev(right); + + case "&": + return ev(left) & ev(right); + + case "^": + return ev(left) ^ ev(right); + + case "+": + return ev(left) + ev(right); + + case "*": + return ev(left) * ev(right); + + case "/": + return ev(left) / ev(right); + + case "%": + return ev(left) % ev(right); + + case "-": + return ev(left) - ev(right); + + case "<<": + return ev(left) << ev(right); + + case ">>": + return ev(left) >> ev(right); + + case ">>>": + return ev(left) >>> ev(right); + + case "==": + return ev(left) == ev(right); + + case "===": + return ev(left) === ev(right); + + case "!=": + return ev(left) != ev(right); + + case "!==": + return ev(left) !== ev(right); + + case "<": + return ev(left) < ev(right); + + case "<=": + return ev(left) <= ev(right); + + case ">": + return ev(left) > ev(right); + + case ">=": + return ev(left) >= ev(right); + + case "in": + return ev(left) in ev(right); + + case "instanceof": + return ev(left) instanceof ev(right); + } + throw def; + }); + def(AST_Conditional, function() { + return ev(this.condition) ? ev(this.consequent) : ev(this.alternative); + }); + def(AST_SymbolRef, function() { + var d = this.definition(); + if (d && d.constant && d.init) return ev(d.init); + throw def; + }); + })(function(node, func) { + node.DEFMETHOD("_eval", func); + }); + (function(def) { + function basic_negation(exp) { + return make_node(AST_UnaryPrefix, exp, { + operator: "!", + expression: exp + }); + } + def(AST_Node, function() { + return basic_negation(this); + }); + def(AST_Statement, function() { + throw new Error("Cannot negate a statement"); + }); + def(AST_Function, function() { + return basic_negation(this); + }); + def(AST_UnaryPrefix, function() { + if (this.operator == "!") return this.expression; + return basic_negation(this); + }); + def(AST_Seq, function(compressor) { + var self = this.clone(); + self.cdr = self.cdr.negate(compressor); + return self; + }); + def(AST_Conditional, function(compressor) { + var self = this.clone(); + self.consequent = self.consequent.negate(compressor); + self.alternative = self.alternative.negate(compressor); + return best_of(basic_negation(this), self); + }); + def(AST_Binary, function(compressor) { + var self = this.clone(), op = this.operator; + if (compressor.option("unsafe_comps")) { + switch (op) { + case "<=": + self.operator = ">"; + return self; + + case "<": + self.operator = ">="; + return self; + + case ">=": + self.operator = "<"; + return self; + + case ">": + self.operator = "<="; + return self; + } + } + switch (op) { + case "==": + self.operator = "!="; + return self; + + case "!=": + self.operator = "=="; + return self; + + case "===": + self.operator = "!=="; + return self; + + case "!==": + self.operator = "==="; + return self; + + case "&&": + self.operator = "||"; + self.left = self.left.negate(compressor); + self.right = self.right.negate(compressor); + return best_of(basic_negation(this), self); + + case "||": + self.operator = "&&"; + self.left = self.left.negate(compressor); + self.right = self.right.negate(compressor); + return best_of(basic_negation(this), self); + } + return basic_negation(this); + }); + })(function(node, func) { + node.DEFMETHOD("negate", function(compressor) { + return func.call(this, compressor); + }); + }); + (function(def) { + def(AST_Node, function() { + return true; + }); + def(AST_EmptyStatement, function() { + return false; + }); + def(AST_Constant, function() { + return false; + }); + def(AST_This, function() { + return false; + }); + def(AST_Block, function() { + for (var i = this.body.length; --i >= 0; ) { + if (this.body[i].has_side_effects()) return true; + } + return false; + }); + def(AST_SimpleStatement, function() { + return this.body.has_side_effects(); + }); + def(AST_Defun, function() { + return true; + }); + def(AST_Function, function() { + return false; + }); + def(AST_Binary, function() { + return this.left.has_side_effects() || this.right.has_side_effects(); + }); + def(AST_Assign, function() { + return true; + }); + def(AST_Conditional, function() { + return this.condition.has_side_effects() || this.consequent.has_side_effects() || this.alternative.has_side_effects(); + }); + def(AST_Unary, function() { + return this.operator == "delete" || this.operator == "++" || this.operator == "--" || this.expression.has_side_effects(); + }); + def(AST_SymbolRef, function() { + return false; + }); + def(AST_Object, function() { + for (var i = this.properties.length; --i >= 0; ) if (this.properties[i].has_side_effects()) return true; + return false; + }); + def(AST_ObjectProperty, function() { + return this.value.has_side_effects(); + }); + def(AST_Array, function() { + for (var i = this.elements.length; --i >= 0; ) if (this.elements[i].has_side_effects()) return true; + return false; + }); + def(AST_PropAccess, function() { + return true; + }); + def(AST_Seq, function() { + return this.car.has_side_effects() || this.cdr.has_side_effects(); + }); + })(function(node, func) { + node.DEFMETHOD("has_side_effects", func); + }); + function aborts(thing) { + return thing && thing.aborts(); + } + (function(def) { + def(AST_Statement, function() { + return null; + }); + def(AST_Jump, function() { + return this; + }); + function block_aborts() { + var n = this.body.length; + return n > 0 && aborts(this.body[n - 1]); + } + def(AST_BlockStatement, block_aborts); + def(AST_SwitchBranch, block_aborts); + def(AST_If, function() { + return this.alternative && aborts(this.body) && aborts(this.alternative); + }); + })(function(node, func) { + node.DEFMETHOD("aborts", func); + }); + OPT(AST_Directive, function(self, compressor) { + if (self.scope.has_directive(self.value) !== self.scope) { + return make_node(AST_EmptyStatement, self); + } + return self; + }); + OPT(AST_Debugger, function(self, compressor) { + if (compressor.option("drop_debugger")) return make_node(AST_EmptyStatement, self); + return self; + }); + OPT(AST_LabeledStatement, function(self, compressor) { + if (self.body instanceof AST_Break && compressor.loopcontrol_target(self.body.label) === self.body) { + return make_node(AST_EmptyStatement, self); + } + return self.label.references.length == 0 ? self.body : self; + }); + OPT(AST_Block, function(self, compressor) { + self.body = tighten_body(self.body, compressor); + return self; + }); + OPT(AST_BlockStatement, function(self, compressor) { + self.body = tighten_body(self.body, compressor); + switch (self.body.length) { + case 1: + return self.body[0]; + + case 0: + return make_node(AST_EmptyStatement, self); + } + return self; + }); + AST_Scope.DEFMETHOD("drop_unused", function(compressor) { + var self = this; + if (compressor.option("unused") && !(self instanceof AST_Toplevel) && !self.uses_eval) { + var in_use = []; + var initializations = new Dictionary(); + var scope = this; + var tw = new TreeWalker(function(node, descend) { + if (node !== self) { + if (node instanceof AST_Defun) { + initializations.add(node.name.name, node); + return true; + } + if (node instanceof AST_Definitions && scope === self) { + node.definitions.forEach(function(def) { + if (def.value) { + initializations.add(def.name.name, def.value); + if (def.value.has_side_effects()) { + def.value.walk(tw); + } + } + }); + return true; + } + if (node instanceof AST_SymbolRef) { + push_uniq(in_use, node.definition()); + return true; + } + if (node instanceof AST_Scope) { + var save_scope = scope; + scope = node; + descend(); + scope = save_scope; + return true; + } + } + }); + self.walk(tw); + for (var i = 0; i < in_use.length; ++i) { + in_use[i].orig.forEach(function(decl) { + var init = initializations.get(decl.name); + if (init) init.forEach(function(init) { + var tw = new TreeWalker(function(node) { + if (node instanceof AST_SymbolRef) { + push_uniq(in_use, node.definition()); + } + }); + init.walk(tw); + }); + }); + } + var tt = new TreeTransformer(function before(node, descend, in_list) { + if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { + for (var a = node.argnames, i = a.length; --i >= 0; ) { + var sym = a[i]; + if (sym.unreferenced()) { + a.pop(); + compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", { + name: sym.name, + file: sym.start.file, + line: sym.start.line, + col: sym.start.col + }); + } else break; + } + } + if (node instanceof AST_Defun && node !== self) { + if (!member(node.name.definition(), in_use)) { + compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", { + name: node.name.name, + file: node.name.start.file, + line: node.name.start.line, + col: node.name.start.col + }); + return make_node(AST_EmptyStatement, node); + } + return node; + } + if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) { + var def = node.definitions.filter(function(def) { + if (member(def.name.definition(), in_use)) return true; + var w = { + name: def.name.name, + file: def.name.start.file, + line: def.name.start.line, + col: def.name.start.col + }; + if (def.value && def.value.has_side_effects()) { + def._unused_side_effects = true; + compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w); + return true; + } + compressor.warn("Dropping unused variable {name} [{file}:{line},{col}]", w); + return false; + }); + def = mergeSort(def, function(a, b) { + if (!a.value && b.value) return -1; + if (!b.value && a.value) return 1; + return 0; + }); + var side_effects = []; + for (var i = 0; i < def.length; ) { + var x = def[i]; + if (x._unused_side_effects) { + side_effects.push(x.value); + def.splice(i, 1); + } else { + if (side_effects.length > 0) { + side_effects.push(x.value); + x.value = AST_Seq.from_array(side_effects); + side_effects = []; + } + ++i; + } + } + if (side_effects.length > 0) { + side_effects = make_node(AST_BlockStatement, node, { + body: [ make_node(AST_SimpleStatement, node, { + body: AST_Seq.from_array(side_effects) + }) ] + }); + } else { + side_effects = null; + } + if (def.length == 0 && !side_effects) { + return make_node(AST_EmptyStatement, node); + } + if (def.length == 0) { + return side_effects; + } + node.definitions = def; + if (side_effects) { + side_effects.body.unshift(node); + node = side_effects; + } + return node; + } + if (node instanceof AST_For && node.init instanceof AST_BlockStatement) { + descend(node, this); + var body = node.init.body.slice(0, -1); + node.init = node.init.body.slice(-1)[0].body; + body.push(node); + return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, { + body: body + }); + } + if (node instanceof AST_Scope && node !== self) return node; + }); + self.transform(tt); + } + }); + AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) { + var hoist_funs = compressor.option("hoist_funs"); + var hoist_vars = compressor.option("hoist_vars"); + var self = this; + if (hoist_funs || hoist_vars) { + var dirs = []; + var hoisted = []; + var vars = new Dictionary(), vars_found = 0, var_decl = 0; + self.walk(new TreeWalker(function(node) { + if (node instanceof AST_Scope && node !== self) return true; + if (node instanceof AST_Var) { + ++var_decl; + return true; + } + })); + hoist_vars = hoist_vars && var_decl > 1; + var tt = new TreeTransformer(function before(node) { + if (node !== self) { + if (node instanceof AST_Directive) { + dirs.push(node); + return make_node(AST_EmptyStatement, node); + } + if (node instanceof AST_Defun && hoist_funs) { + hoisted.push(node); + return make_node(AST_EmptyStatement, node); + } + if (node instanceof AST_Var && hoist_vars) { + node.definitions.forEach(function(def) { + vars.set(def.name.name, def); + ++vars_found; + }); + var seq = node.to_assignments(); + var p = tt.parent(); + if (p instanceof AST_ForIn && p.init === node) { + if (seq == null) return node.definitions[0].name; + return seq; + } + if (p instanceof AST_For && p.init === node) { + return seq; + } + if (!seq) return make_node(AST_EmptyStatement, node); + return make_node(AST_SimpleStatement, node, { + body: seq + }); + } + if (node instanceof AST_Scope) return node; + } + }); + self = self.transform(tt); + if (vars_found > 0) { + var defs = []; + vars.each(function(def, name) { + if (self instanceof AST_Lambda && find_if(function(x) { + return x.name == def.name.name; + }, self.argnames)) { + vars.del(name); + } else { + def = def.clone(); + def.value = null; + defs.push(def); + vars.set(name, def); + } + }); + if (defs.length > 0) { + for (var i = 0; i < self.body.length; ) { + if (self.body[i] instanceof AST_SimpleStatement) { + var expr = self.body[i].body, sym, assign; + if (expr instanceof AST_Assign && expr.operator == "=" && (sym = expr.left) instanceof AST_Symbol && vars.has(sym.name)) { + var def = vars.get(sym.name); + if (def.value) break; + def.value = expr.right; + remove(defs, def); + defs.push(def); + self.body.splice(i, 1); + continue; + } + if (expr instanceof AST_Seq && (assign = expr.car) instanceof AST_Assign && assign.operator == "=" && (sym = assign.left) instanceof AST_Symbol && vars.has(sym.name)) { + var def = vars.get(sym.name); + if (def.value) break; + def.value = assign.right; + remove(defs, def); + defs.push(def); + self.body[i].body = expr.cdr; + continue; + } + } + if (self.body[i] instanceof AST_EmptyStatement) { + self.body.splice(i, 1); + continue; + } + if (self.body[i] instanceof AST_BlockStatement) { + var tmp = [ i, 1 ].concat(self.body[i].body); + self.body.splice.apply(self.body, tmp); + continue; + } + break; + } + defs = make_node(AST_Var, self, { + definitions: defs + }); + hoisted.push(defs); + } + } + self.body = dirs.concat(hoisted, self.body); + } + return self; + }); + OPT(AST_SimpleStatement, function(self, compressor) { + if (compressor.option("side_effects")) { + if (!self.body.has_side_effects()) { + compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start); + return make_node(AST_EmptyStatement, self); + } + } + return self; + }); + OPT(AST_DWLoop, function(self, compressor) { + var cond = self.condition.evaluate(compressor); + self.condition = cond[0]; + if (!compressor.option("loops")) return self; + if (cond.length > 1) { + if (cond[1]) { + return make_node(AST_For, self, { + body: self.body + }); + } else if (self instanceof AST_While) { + if (compressor.option("dead_code")) { + var a = []; + extract_declarations_from_unreachable_code(compressor, self.body, a); + return make_node(AST_BlockStatement, self, { + body: a + }); + } + } + } + return self; + }); + function if_break_in_loop(self, compressor) { + function drop_it(rest) { + rest = as_statement_array(rest); + if (self.body instanceof AST_BlockStatement) { + self.body = self.body.clone(); + self.body.body = rest.concat(self.body.body.slice(1)); + self.body = self.body.transform(compressor); + } else { + self.body = make_node(AST_BlockStatement, self.body, { + body: rest + }).transform(compressor); + } + if_break_in_loop(self, compressor); + } + var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body; + if (first instanceof AST_If) { + if (first.body instanceof AST_Break && compressor.loopcontrol_target(first.body.label) === self) { + if (self.condition) { + self.condition = make_node(AST_Binary, self.condition, { + left: self.condition, + operator: "&&", + right: first.condition.negate(compressor) + }); + } else { + self.condition = first.condition.negate(compressor); + } + drop_it(first.alternative); + } else if (first.alternative instanceof AST_Break && compressor.loopcontrol_target(first.alternative.label) === self) { + if (self.condition) { + self.condition = make_node(AST_Binary, self.condition, { + left: self.condition, + operator: "&&", + right: first.condition + }); + } else { + self.condition = first.condition; + } + drop_it(first.body); + } + } + } + OPT(AST_While, function(self, compressor) { + if (!compressor.option("loops")) return self; + self = AST_DWLoop.prototype.optimize.call(self, compressor); + if (self instanceof AST_While) { + if_break_in_loop(self, compressor); + self = make_node(AST_For, self, self).transform(compressor); + } + return self; + }); + OPT(AST_For, function(self, compressor) { + var cond = self.condition; + if (cond) { + cond = cond.evaluate(compressor); + self.condition = cond[0]; + } + if (!compressor.option("loops")) return self; + if (cond) { + if (cond.length > 1 && !cond[1]) { + if (compressor.option("dead_code")) { + var a = []; + if (self.init instanceof AST_Statement) { + a.push(self.init); + } else if (self.init) { + a.push(make_node(AST_SimpleStatement, self.init, { + body: self.init + })); + } + extract_declarations_from_unreachable_code(compressor, self.body, a); + return make_node(AST_BlockStatement, self, { + body: a + }); + } + } + } + if_break_in_loop(self, compressor); + return self; + }); + OPT(AST_If, function(self, compressor) { + if (!compressor.option("conditionals")) return self; + var cond = self.condition.evaluate(compressor); + self.condition = cond[0]; + if (cond.length > 1) { + if (cond[1]) { + compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start); + if (compressor.option("dead_code")) { + var a = []; + if (self.alternative) { + extract_declarations_from_unreachable_code(compressor, self.alternative, a); + } + a.push(self.body); + return make_node(AST_BlockStatement, self, { + body: a + }).transform(compressor); + } + } else { + compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start); + if (compressor.option("dead_code")) { + var a = []; + extract_declarations_from_unreachable_code(compressor, self.body, a); + if (self.alternative) a.push(self.alternative); + return make_node(AST_BlockStatement, self, { + body: a + }).transform(compressor); + } + } + } + if (is_empty(self.alternative)) self.alternative = null; + var negated = self.condition.negate(compressor); + var negated_is_best = best_of(self.condition, negated) === negated; + if (self.alternative && negated_is_best) { + negated_is_best = false; + self.condition = negated; + var tmp = self.body; + self.body = self.alternative || make_node(AST_EmptyStatement); + self.alternative = tmp; + } + if (is_empty(self.body) && is_empty(self.alternative)) { + return make_node(AST_SimpleStatement, self.condition, { + body: self.condition + }).transform(compressor); + } + if (self.body instanceof AST_SimpleStatement && self.alternative instanceof AST_SimpleStatement) { + return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Conditional, self, { + condition: self.condition, + consequent: self.body.body, + alternative: self.alternative.body + }) + }).transform(compressor); + } + if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) { + if (negated_is_best) return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Binary, self, { + operator: "||", + left: negated, + right: self.body.body + }) + }).transform(compressor); + return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Binary, self, { + operator: "&&", + left: self.condition, + right: self.body.body + }) + }).transform(compressor); + } + if (self.body instanceof AST_EmptyStatement && self.alternative && self.alternative instanceof AST_SimpleStatement) { + return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Binary, self, { + operator: "||", + left: self.condition, + right: self.alternative.body + }) + }).transform(compressor); + } + if (self.body instanceof AST_Exit && self.alternative instanceof AST_Exit && self.body.TYPE == self.alternative.TYPE) { + return make_node(self.body.CTOR, self, { + value: make_node(AST_Conditional, self, { + condition: self.condition, + consequent: self.body.value || make_node(AST_Undefined, self.body).optimize(compressor), + alternative: self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor) + }) + }).transform(compressor); + } + if (self.body instanceof AST_If && !self.body.alternative && !self.alternative) { + self.condition = make_node(AST_Binary, self.condition, { + operator: "&&", + left: self.condition, + right: self.body.condition + }).transform(compressor); + self.body = self.body.body; + } + if (aborts(self.body)) { + if (self.alternative) { + var alt = self.alternative; + self.alternative = null; + return make_node(AST_BlockStatement, self, { + body: [ self, alt ] + }).transform(compressor); + } + } + if (aborts(self.alternative)) { + var body = self.body; + self.body = self.alternative; + self.condition = negated_is_best ? negated : self.condition.negate(compressor); + self.alternative = null; + return make_node(AST_BlockStatement, self, { + body: [ self, body ] + }).transform(compressor); + } + return self; + }); + OPT(AST_Switch, function(self, compressor) { + if (self.body.length == 0 && compressor.option("conditionals")) { + return make_node(AST_SimpleStatement, self, { + body: self.expression + }).transform(compressor); + } + for (;;) { + var last_branch = self.body[self.body.length - 1]; + if (last_branch) { + var stat = last_branch.body[last_branch.body.length - 1]; + if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self) last_branch.body.pop(); + if (last_branch instanceof AST_Default && last_branch.body.length == 0) { + self.body.pop(); + continue; + } + } + break; + } + var exp = self.expression.evaluate(compressor); + out: if (exp.length == 2) try { + self.expression = exp[0]; + if (!compressor.option("dead_code")) break out; + var value = exp[1]; + var in_if = false; + var in_block = false; + var started = false; + var stopped = false; + var ruined = false; + var tt = new TreeTransformer(function(node, descend, in_list) { + if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) { + return node; + } else if (node instanceof AST_Switch && node === self) { + node = node.clone(); + descend(node, this); + return ruined ? node : make_node(AST_BlockStatement, node, { + body: node.body.reduce(function(a, branch) { + return a.concat(branch.body); + }, []) + }).transform(compressor); + } else if (node instanceof AST_If || node instanceof AST_Try) { + var save = in_if; + in_if = !in_block; + descend(node, this); + in_if = save; + return node; + } else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch) { + var save = in_block; + in_block = true; + descend(node, this); + in_block = save; + return node; + } else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) { + if (in_if) { + ruined = true; + return node; + } + if (in_block) return node; + stopped = true; + return in_list ? MAP.skip : make_node(AST_EmptyStatement, node); + } else if (node instanceof AST_SwitchBranch && this.parent() === self) { + if (stopped) return MAP.skip; + if (node instanceof AST_Case) { + var exp = node.expression.evaluate(compressor); + if (exp.length < 2) { + throw self; + } + if (exp[1] === value || started) { + started = true; + if (aborts(node)) stopped = true; + descend(node, this); + return node; + } + return MAP.skip; + } + descend(node, this); + return node; + } + }); + tt.stack = compressor.stack.slice(); + self = self.transform(tt); + } catch (ex) { + if (ex !== self) throw ex; + } + return self; + }); + OPT(AST_Case, function(self, compressor) { + self.body = tighten_body(self.body, compressor); + return self; + }); + OPT(AST_Try, function(self, compressor) { + self.body = tighten_body(self.body, compressor); + return self; + }); + AST_Definitions.DEFMETHOD("remove_initializers", function() { + this.definitions.forEach(function(def) { + def.value = null; + }); + }); + AST_Definitions.DEFMETHOD("to_assignments", function() { + var assignments = this.definitions.reduce(function(a, def) { + if (def.value) { + var name = make_node(AST_SymbolRef, def.name, def.name); + a.push(make_node(AST_Assign, def, { + operator: "=", + left: name, + right: def.value + })); + } + return a; + }, []); + if (assignments.length == 0) return null; + return AST_Seq.from_array(assignments); + }); + OPT(AST_Definitions, function(self, compressor) { + if (self.definitions.length == 0) return make_node(AST_EmptyStatement, self); + return self; + }); + OPT(AST_Function, function(self, compressor) { + self = AST_Lambda.prototype.optimize.call(self, compressor); + if (compressor.option("unused")) { + if (self.name && self.name.unreferenced()) { + self.name = null; + } + } + return self; + }); + OPT(AST_Call, function(self, compressor) { + if (compressor.option("unsafe")) { + var exp = self.expression; + if (exp instanceof AST_SymbolRef && exp.undeclared()) { + switch (exp.name) { + case "Array": + if (self.args.length != 1) { + return make_node(AST_Array, self, { + elements: self.args + }); + } + break; + + case "Object": + if (self.args.length == 0) { + return make_node(AST_Object, self, { + properties: [] + }); + } + break; + + case "String": + if (self.args.length == 0) return make_node(AST_String, self, { + value: "" + }); + return make_node(AST_Binary, self, { + left: self.args[0], + operator: "+", + right: make_node(AST_String, self, { + value: "" + }) + }); + + case "Function": + if (all(self.args, function(x) { + return x instanceof AST_String; + })) { + try { + var code = "(function(" + self.args.slice(0, -1).map(function(arg) { + return arg.value; + }).join(",") + "){" + self.args[self.args.length - 1].value + "})()"; + var ast = parse(code); + ast.figure_out_scope(); + var comp = new Compressor(compressor.options); + ast = ast.transform(comp); + ast.figure_out_scope(); + ast.mangle_names(); + var fun = ast.body[0].body.expression; + var args = fun.argnames.map(function(arg, i) { + return make_node(AST_String, self.args[i], { + value: arg.print_to_string() + }); + }); + var code = OutputStream(); + AST_BlockStatement.prototype._codegen.call(fun, fun, code); + code = code.toString().replace(/^\{|\}$/g, ""); + args.push(make_node(AST_String, self.args[self.args.length - 1], { + value: code + })); + self.args = args; + return self; + } catch (ex) { + if (ex instanceof JS_Parse_Error) { + compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start); + compressor.warn(ex.toString()); + } else { + console.log(ex); + } + } + } + break; + } + } else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) { + return make_node(AST_Binary, self, { + left: make_node(AST_String, self, { + value: "" + }), + operator: "+", + right: exp.expression + }).transform(compressor); + } + } + if (compressor.option("side_effects")) { + if (self.expression instanceof AST_Function && self.args.length == 0 && !AST_Block.prototype.has_side_effects.call(self.expression)) { + return make_node(AST_Undefined, self).transform(compressor); + } + } + return self; + }); + OPT(AST_New, function(self, compressor) { + if (compressor.option("unsafe")) { + var exp = self.expression; + if (exp instanceof AST_SymbolRef && exp.undeclared()) { + switch (exp.name) { + case "Object": + case "RegExp": + case "Function": + case "Error": + case "Array": + return make_node(AST_Call, self, self).transform(compressor); + } + } + } + return self; + }); + OPT(AST_Seq, function(self, compressor) { + if (!compressor.option("side_effects")) return self; + if (!self.car.has_side_effects()) { + var p; + if (!(self.cdr instanceof AST_SymbolRef && self.cdr.name == "eval" && self.cdr.undeclared() && (p = compressor.parent()) instanceof AST_Call && p.expression === self)) { + return self.cdr; + } + } + if (compressor.option("cascade")) { + if (self.car instanceof AST_Assign && !self.car.left.has_side_effects() && self.car.left.equivalent_to(self.cdr)) { + return self.car; + } + if (!self.car.has_side_effects() && !self.cdr.has_side_effects() && self.car.equivalent_to(self.cdr)) { + return self.car; + } + } + return self; + }); + AST_Unary.DEFMETHOD("lift_sequences", function(compressor) { + if (compressor.option("sequences")) { + if (this.expression instanceof AST_Seq) { + var seq = this.expression; + var x = seq.to_array(); + this.expression = x.pop(); + x.push(this); + seq = AST_Seq.from_array(x).transform(compressor); + return seq; + } + } + return this; + }); + OPT(AST_UnaryPostfix, function(self, compressor) { + return self.lift_sequences(compressor); + }); + OPT(AST_UnaryPrefix, function(self, compressor) { + self = self.lift_sequences(compressor); + var e = self.expression; + if (compressor.option("booleans") && compressor.in_boolean_context()) { + switch (self.operator) { + case "!": + if (e instanceof AST_UnaryPrefix && e.operator == "!") { + return e.expression; + } + break; + + case "typeof": + compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start); + return make_node(AST_True, self); + } + if (e instanceof AST_Binary && self.operator == "!") { + self = best_of(self, e.negate(compressor)); + } + } + return self.evaluate(compressor)[0]; + }); + AST_Binary.DEFMETHOD("lift_sequences", function(compressor) { + if (compressor.option("sequences")) { + if (this.left instanceof AST_Seq) { + var seq = this.left; + var x = seq.to_array(); + this.left = x.pop(); + x.push(this); + seq = AST_Seq.from_array(x).transform(compressor); + return seq; + } + if (this.right instanceof AST_Seq && !(this.operator == "||" || this.operator == "&&") && !this.left.has_side_effects()) { + var seq = this.right; + var x = seq.to_array(); + this.right = x.pop(); + x.push(this); + seq = AST_Seq.from_array(x).transform(compressor); + return seq; + } + } + return this; + }); + var commutativeOperators = makePredicate("== === != !== * & | ^"); + OPT(AST_Binary, function(self, compressor) { + var reverse = compressor.has_directive("use asm") ? noop : function(op, force) { + if (force || !(self.left.has_side_effects() || self.right.has_side_effects())) { + if (op) self.operator = op; + var tmp = self.left; + self.left = self.right; + self.right = tmp; + } + }; + if (commutativeOperators(self.operator)) { + if (self.right instanceof AST_Constant && !(self.left instanceof AST_Constant)) { + reverse(null, true); + } + } + self = self.lift_sequences(compressor); + if (compressor.option("comparisons")) switch (self.operator) { + case "===": + case "!==": + if (self.left.is_string(compressor) && self.right.is_string(compressor) || self.left.is_boolean() && self.right.is_boolean()) { + self.operator = self.operator.substr(0, 2); + } + + case "==": + case "!=": + if (self.left instanceof AST_String && self.left.value == "undefined" && self.right instanceof AST_UnaryPrefix && self.right.operator == "typeof" && compressor.option("unsafe")) { + if (!(self.right.expression instanceof AST_SymbolRef) || !self.right.expression.undeclared()) { + self.right = self.right.expression; + self.left = make_node(AST_Undefined, self.left).optimize(compressor); + if (self.operator.length == 2) self.operator += "="; + } + } + break; + } + if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) { + case "&&": + var ll = self.left.evaluate(compressor); + var rr = self.right.evaluate(compressor); + if (ll.length > 1 && !ll[1] || rr.length > 1 && !rr[1]) { + compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start); + return make_node(AST_False, self); + } + if (ll.length > 1 && ll[1]) { + return rr[0]; + } + if (rr.length > 1 && rr[1]) { + return ll[0]; + } + break; + + case "||": + var ll = self.left.evaluate(compressor); + var rr = self.right.evaluate(compressor); + if (ll.length > 1 && ll[1] || rr.length > 1 && rr[1]) { + compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start); + return make_node(AST_True, self); + } + if (ll.length > 1 && !ll[1]) { + return rr[0]; + } + if (rr.length > 1 && !rr[1]) { + return ll[0]; + } + break; + + case "+": + var ll = self.left.evaluate(compressor); + var rr = self.right.evaluate(compressor); + if (ll.length > 1 && ll[0] instanceof AST_String && ll[1] || rr.length > 1 && rr[0] instanceof AST_String && rr[1]) { + compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); + return make_node(AST_True, self); + } + break; + } + var exp = self.evaluate(compressor); + if (exp.length > 1) { + if (best_of(exp[0], self) !== self) return exp[0]; + } + if (compressor.option("comparisons")) { + if (!(compressor.parent() instanceof AST_Binary) || compressor.parent() instanceof AST_Assign) { + var negated = make_node(AST_UnaryPrefix, self, { + operator: "!", + expression: self.negate(compressor) + }); + self = best_of(self, negated); + } + switch (self.operator) { + case "<": + reverse(">"); + break; + + case "<=": + reverse(">="); + break; + } + } + if (self.operator == "+" && self.right instanceof AST_String && self.right.getValue() === "" && self.left instanceof AST_Binary && self.left.operator == "+" && self.left.is_string(compressor)) { + return self.left; + } + return self; + }); + OPT(AST_SymbolRef, function(self, compressor) { + if (self.undeclared()) { + var defines = compressor.option("global_defs"); + if (defines && defines.hasOwnProperty(self.name)) { + return make_node_from_constant(compressor, defines[self.name], self); + } + switch (self.name) { + case "undefined": + return make_node(AST_Undefined, self); + + case "NaN": + return make_node(AST_NaN, self); + + case "Infinity": + return make_node(AST_Infinity, self); + } + } + return self; + }); + OPT(AST_Undefined, function(self, compressor) { + if (compressor.option("unsafe")) { + var scope = compressor.find_parent(AST_Scope); + var undef = scope.find_variable("undefined"); + if (undef) { + var ref = make_node(AST_SymbolRef, self, { + name: "undefined", + scope: scope, + thedef: undef + }); + ref.reference(); + return ref; + } + } + return self; + }); + var ASSIGN_OPS = [ "+", "-", "/", "*", "%", ">>", "<<", ">>>", "|", "^", "&" ]; + OPT(AST_Assign, function(self, compressor) { + self = self.lift_sequences(compressor); + if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary && self.right.left instanceof AST_SymbolRef && self.right.left.name == self.left.name && member(self.right.operator, ASSIGN_OPS)) { + self.operator = self.right.operator + "="; + self.right = self.right.right; + } + return self; + }); + OPT(AST_Conditional, function(self, compressor) { + if (!compressor.option("conditionals")) return self; + if (self.condition instanceof AST_Seq) { + var car = self.condition.car; + self.condition = self.condition.cdr; + return AST_Seq.cons(car, self); + } + var cond = self.condition.evaluate(compressor); + if (cond.length > 1) { + if (cond[1]) { + compressor.warn("Condition always true [{file}:{line},{col}]", self.start); + return self.consequent; + } else { + compressor.warn("Condition always false [{file}:{line},{col}]", self.start); + return self.alternative; + } + } + var negated = cond[0].negate(compressor); + if (best_of(cond[0], negated) === negated) { + self = make_node(AST_Conditional, self, { + condition: negated, + consequent: self.alternative, + alternative: self.consequent + }); + } + var consequent = self.consequent; + var alternative = self.alternative; + if (consequent instanceof AST_Assign && alternative instanceof AST_Assign && consequent.operator == alternative.operator && consequent.left.equivalent_to(alternative.left)) { + self = make_node(AST_Assign, self, { + operator: consequent.operator, + left: consequent.left, + right: make_node(AST_Conditional, self, { + condition: self.condition, + consequent: consequent.right, + alternative: alternative.right + }) + }); + } + return self; + }); + OPT(AST_Boolean, function(self, compressor) { + if (compressor.option("booleans")) { + var p = compressor.parent(); + if (p instanceof AST_Binary && (p.operator == "==" || p.operator == "!=")) { + compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", { + operator: p.operator, + value: self.value, + file: p.start.file, + line: p.start.line, + col: p.start.col + }); + return make_node(AST_Number, self, { + value: +self.value + }); + } + return make_node(AST_UnaryPrefix, self, { + operator: "!", + expression: make_node(AST_Number, self, { + value: 1 - self.value + }) + }); + } + return self; + }); + OPT(AST_Sub, function(self, compressor) { + var prop = self.property; + if (prop instanceof AST_String && compressor.option("properties")) { + prop = prop.getValue(); + if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) { + return make_node(AST_Dot, self, { + expression: self.expression, + property: prop + }); + } + } + return self; + }); + function literals_in_boolean_context(self, compressor) { + if (compressor.option("booleans") && compressor.in_boolean_context()) { + return make_node(AST_True, self); + } + return self; + } + OPT(AST_Array, literals_in_boolean_context); + OPT(AST_Object, literals_in_boolean_context); + OPT(AST_RegExp, literals_in_boolean_context); + })(); + "use strict"; + function SourceMap(options) { + options = defaults(options, { + file: null, + root: null, + orig: null + }); + var generator = new MOZ_SourceMap.SourceMapGenerator({ + file: options.file, + sourceRoot: options.root + }); + var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig); + function add(source, gen_line, gen_col, orig_line, orig_col, name) { + if (orig_map) { + var info = orig_map.originalPositionFor({ + line: orig_line, + column: orig_col + }); + source = info.source; + orig_line = info.line; + orig_col = info.column; + name = info.name; + } + generator.addMapping({ + generated: { + line: gen_line, + column: gen_col + }, + original: { + line: orig_line, + column: orig_col + }, + source: source, + name: name + }); + } + return { + add: add, + get: function() { + return generator; + }, + toString: function() { + return generator.toString(); + } + }; + } + "use strict"; + (function() { + var MOZ_TO_ME = { + TryStatement: function(M) { + return new AST_Try({ + start: my_start_token(M), + end: my_end_token(M), + body: from_moz(M.block).body, + bcatch: from_moz(M.handlers[0]), + bfinally: M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null + }); + }, + CatchClause: function(M) { + return new AST_Catch({ + start: my_start_token(M), + end: my_end_token(M), + argname: from_moz(M.param), + body: from_moz(M.body).body + }); + }, + ObjectExpression: function(M) { + return new AST_Object({ + start: my_start_token(M), + end: my_end_token(M), + properties: M.properties.map(function(prop) { + var key = prop.key; + var name = key.type == "Identifier" ? key.name : key.value; + var args = { + start: my_start_token(key), + end: my_end_token(prop.value), + key: name, + value: from_moz(prop.value) + }; + switch (prop.kind) { + case "init": + return new AST_ObjectKeyVal(args); + + case "set": + args.value.name = from_moz(key); + return new AST_ObjectSetter(args); + + case "get": + args.value.name = from_moz(key); + return new AST_ObjectGetter(args); + } + }) + }); + }, + SequenceExpression: function(M) { + return AST_Seq.from_array(M.expressions.map(from_moz)); + }, + MemberExpression: function(M) { + return new (M.computed ? AST_Sub : AST_Dot)({ + start: my_start_token(M), + end: my_end_token(M), + property: M.computed ? from_moz(M.property) : M.property.name, + expression: from_moz(M.object) + }); + }, + SwitchCase: function(M) { + return new (M.test ? AST_Case : AST_Default)({ + start: my_start_token(M), + end: my_end_token(M), + expression: from_moz(M.test), + body: M.consequent.map(from_moz) + }); + }, + Literal: function(M) { + var val = M.value, args = { + start: my_start_token(M), + end: my_end_token(M) + }; + if (val === null) return new AST_Null(args); + switch (typeof val) { + case "string": + args.value = val; + return new AST_String(args); + + case "number": + args.value = val; + return new AST_Number(args); + + case "boolean": + return new (val ? AST_True : AST_False)(args); + + default: + args.value = val; + return new AST_RegExp(args); + } + }, + UnaryExpression: From_Moz_Unary, + UpdateExpression: From_Moz_Unary, + Identifier: function(M) { + var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2]; + return new (M.name == "this" ? AST_This : p.type == "LabeledStatement" ? AST_Label : p.type == "VariableDeclarator" && p.id === M ? p.kind == "const" ? AST_SymbolConst : AST_SymbolVar : p.type == "FunctionExpression" ? p.id === M ? AST_SymbolLambda : AST_SymbolFunarg : p.type == "FunctionDeclaration" ? p.id === M ? AST_SymbolDefun : AST_SymbolFunarg : p.type == "CatchClause" ? AST_SymbolCatch : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef : AST_SymbolRef)({ + start: my_start_token(M), + end: my_end_token(M), + name: M.name + }); + } + }; + function From_Moz_Unary(M) { + var prefix = "prefix" in M ? M.prefix : M.type == "UnaryExpression" ? true : false; + return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({ + start: my_start_token(M), + end: my_end_token(M), + operator: M.operator, + expression: from_moz(M.argument) + }); + } + var ME_TO_MOZ = {}; + map("Node", AST_Node); + map("Program", AST_Toplevel, "body@body"); + map("Function", AST_Function, "id>name, params@argnames, body%body"); + map("EmptyStatement", AST_EmptyStatement); + map("BlockStatement", AST_BlockStatement, "body@body"); + map("ExpressionStatement", AST_SimpleStatement, "expression>body"); + map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative"); + map("LabeledStatement", AST_LabeledStatement, "label>label, body>body"); + map("BreakStatement", AST_Break, "label>label"); + map("ContinueStatement", AST_Continue, "label>label"); + map("WithStatement", AST_With, "object>expression, body>body"); + map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body"); + map("ReturnStatement", AST_Return, "argument>value"); + map("ThrowStatement", AST_Throw, "argument>value"); + map("WhileStatement", AST_While, "test>condition, body>body"); + map("DoWhileStatement", AST_Do, "test>condition, body>body"); + map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body"); + map("ForInStatement", AST_ForIn, "left>init, right>object, body>body"); + map("DebuggerStatement", AST_Debugger); + map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body"); + map("VariableDeclaration", AST_Var, "declarations@definitions"); + map("VariableDeclarator", AST_VarDef, "id>name, init>value"); + map("ThisExpression", AST_This); + map("ArrayExpression", AST_Array, "elements@elements"); + map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body"); + map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right"); + map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right"); + map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right"); + map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative"); + map("NewExpression", AST_New, "callee>expression, arguments@args"); + map("CallExpression", AST_Call, "callee>expression, arguments@args"); + function my_start_token(moznode) { + return new AST_Token({ + file: moznode.loc && moznode.loc.source, + line: moznode.loc && moznode.loc.start.line, + col: moznode.loc && moznode.loc.start.column, + pos: moznode.start, + endpos: moznode.start + }); + } + function my_end_token(moznode) { + return new AST_Token({ + file: moznode.loc && moznode.loc.source, + line: moznode.loc && moznode.loc.end.line, + col: moznode.loc && moznode.loc.end.column, + pos: moznode.end, + endpos: moznode.end + }); + } + function map(moztype, mytype, propmap) { + var moz_to_me = "function From_Moz_" + moztype + "(M){\n"; + moz_to_me += "return new mytype({\n" + "start: my_start_token(M),\n" + "end: my_end_token(M)"; + if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop) { + var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop); + if (!m) throw new Error("Can't understand property map: " + prop); + var moz = "M." + m[1], how = m[2], my = m[3]; + moz_to_me += ",\n" + my + ": "; + if (how == "@") { + moz_to_me += moz + ".map(from_moz)"; + } else if (how == ">") { + moz_to_me += "from_moz(" + moz + ")"; + } else if (how == "=") { + moz_to_me += moz; + } else if (how == "%") { + moz_to_me += "from_moz(" + moz + ").body"; + } else throw new Error("Can't understand operator in propmap: " + prop); + }); + moz_to_me += "\n})}"; + moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(mytype, my_start_token, my_end_token, from_moz); + return MOZ_TO_ME[moztype] = moz_to_me; + } + var FROM_MOZ_STACK = null; + function from_moz(node) { + FROM_MOZ_STACK.push(node); + var ret = node != null ? MOZ_TO_ME[node.type](node) : null; + FROM_MOZ_STACK.pop(); + return ret; + } + AST_Node.from_mozilla_ast = function(node) { + var save_stack = FROM_MOZ_STACK; + FROM_MOZ_STACK = []; + var ast = from_moz(node); + FROM_MOZ_STACK = save_stack; + return ast; + }; + })(); + exports["array_to_hash"] = array_to_hash; + exports["slice"] = slice; + exports["characters"] = characters; + exports["member"] = member; + exports["find_if"] = find_if; + exports["repeat_string"] = repeat_string; + exports["DefaultsError"] = DefaultsError; + exports["defaults"] = defaults; + exports["merge"] = merge; + exports["noop"] = noop; + exports["MAP"] = MAP; + exports["push_uniq"] = push_uniq; + exports["string_template"] = string_template; + exports["remove"] = remove; + exports["mergeSort"] = mergeSort; + exports["set_difference"] = set_difference; + exports["set_intersection"] = set_intersection; + exports["makePredicate"] = makePredicate; + exports["all"] = all; + exports["Dictionary"] = Dictionary; + exports["DEFNODE"] = DEFNODE; + exports["AST_Token"] = AST_Token; + exports["AST_Node"] = AST_Node; + exports["AST_Statement"] = AST_Statement; + exports["AST_Debugger"] = AST_Debugger; + exports["AST_Directive"] = AST_Directive; + exports["AST_SimpleStatement"] = AST_SimpleStatement; + exports["walk_body"] = walk_body; + exports["AST_Block"] = AST_Block; + exports["AST_BlockStatement"] = AST_BlockStatement; + exports["AST_EmptyStatement"] = AST_EmptyStatement; + exports["AST_StatementWithBody"] = AST_StatementWithBody; + exports["AST_LabeledStatement"] = AST_LabeledStatement; + exports["AST_DWLoop"] = AST_DWLoop; + exports["AST_Do"] = AST_Do; + exports["AST_While"] = AST_While; + exports["AST_For"] = AST_For; + exports["AST_ForIn"] = AST_ForIn; + exports["AST_With"] = AST_With; + exports["AST_Scope"] = AST_Scope; + exports["AST_Toplevel"] = AST_Toplevel; + exports["AST_Lambda"] = AST_Lambda; + exports["AST_Accessor"] = AST_Accessor; + exports["AST_Function"] = AST_Function; + exports["AST_Defun"] = AST_Defun; + exports["AST_Jump"] = AST_Jump; + exports["AST_Exit"] = AST_Exit; + exports["AST_Return"] = AST_Return; + exports["AST_Throw"] = AST_Throw; + exports["AST_LoopControl"] = AST_LoopControl; + exports["AST_Break"] = AST_Break; + exports["AST_Continue"] = AST_Continue; + exports["AST_If"] = AST_If; + exports["AST_Switch"] = AST_Switch; + exports["AST_SwitchBranch"] = AST_SwitchBranch; + exports["AST_Default"] = AST_Default; + exports["AST_Case"] = AST_Case; + exports["AST_Try"] = AST_Try; + exports["AST_Catch"] = AST_Catch; + exports["AST_Finally"] = AST_Finally; + exports["AST_Definitions"] = AST_Definitions; + exports["AST_Var"] = AST_Var; + exports["AST_Const"] = AST_Const; + exports["AST_VarDef"] = AST_VarDef; + exports["AST_Call"] = AST_Call; + exports["AST_New"] = AST_New; + exports["AST_Seq"] = AST_Seq; + exports["AST_PropAccess"] = AST_PropAccess; + exports["AST_Dot"] = AST_Dot; + exports["AST_Sub"] = AST_Sub; + exports["AST_Unary"] = AST_Unary; + exports["AST_UnaryPrefix"] = AST_UnaryPrefix; + exports["AST_UnaryPostfix"] = AST_UnaryPostfix; + exports["AST_Binary"] = AST_Binary; + exports["AST_Conditional"] = AST_Conditional; + exports["AST_Assign"] = AST_Assign; + exports["AST_Array"] = AST_Array; + exports["AST_Object"] = AST_Object; + exports["AST_ObjectProperty"] = AST_ObjectProperty; + exports["AST_ObjectKeyVal"] = AST_ObjectKeyVal; + exports["AST_ObjectSetter"] = AST_ObjectSetter; + exports["AST_ObjectGetter"] = AST_ObjectGetter; + exports["AST_Symbol"] = AST_Symbol; + exports["AST_SymbolAccessor"] = AST_SymbolAccessor; + exports["AST_SymbolDeclaration"] = AST_SymbolDeclaration; + exports["AST_SymbolVar"] = AST_SymbolVar; + exports["AST_SymbolConst"] = AST_SymbolConst; + exports["AST_SymbolFunarg"] = AST_SymbolFunarg; + exports["AST_SymbolDefun"] = AST_SymbolDefun; + exports["AST_SymbolLambda"] = AST_SymbolLambda; + exports["AST_SymbolCatch"] = AST_SymbolCatch; + exports["AST_Label"] = AST_Label; + exports["AST_SymbolRef"] = AST_SymbolRef; + exports["AST_LabelRef"] = AST_LabelRef; + exports["AST_This"] = AST_This; + exports["AST_Constant"] = AST_Constant; + exports["AST_String"] = AST_String; + exports["AST_Number"] = AST_Number; + exports["AST_RegExp"] = AST_RegExp; + exports["AST_Atom"] = AST_Atom; + exports["AST_Null"] = AST_Null; + exports["AST_NaN"] = AST_NaN; + exports["AST_Undefined"] = AST_Undefined; + exports["AST_Hole"] = AST_Hole; + exports["AST_Infinity"] = AST_Infinity; + exports["AST_Boolean"] = AST_Boolean; + exports["AST_False"] = AST_False; + exports["AST_True"] = AST_True; + exports["TreeWalker"] = TreeWalker; + exports["KEYWORDS"] = KEYWORDS; + exports["KEYWORDS_ATOM"] = KEYWORDS_ATOM; + exports["RESERVED_WORDS"] = RESERVED_WORDS; + exports["KEYWORDS_BEFORE_EXPRESSION"] = KEYWORDS_BEFORE_EXPRESSION; + exports["OPERATOR_CHARS"] = OPERATOR_CHARS; + exports["RE_HEX_NUMBER"] = RE_HEX_NUMBER; + exports["RE_OCT_NUMBER"] = RE_OCT_NUMBER; + exports["RE_DEC_NUMBER"] = RE_DEC_NUMBER; + exports["OPERATORS"] = OPERATORS; + exports["WHITESPACE_CHARS"] = WHITESPACE_CHARS; + exports["PUNC_BEFORE_EXPRESSION"] = PUNC_BEFORE_EXPRESSION; + exports["PUNC_CHARS"] = PUNC_CHARS; + exports["REGEXP_MODIFIERS"] = REGEXP_MODIFIERS; + exports["UNICODE"] = UNICODE; + exports["is_letter"] = is_letter; + exports["is_digit"] = is_digit; + exports["is_alphanumeric_char"] = is_alphanumeric_char; + exports["is_unicode_combining_mark"] = is_unicode_combining_mark; + exports["is_unicode_connector_punctuation"] = is_unicode_connector_punctuation; + exports["is_identifier"] = is_identifier; + exports["is_identifier_start"] = is_identifier_start; + exports["is_identifier_char"] = is_identifier_char; + exports["is_identifier_string"] = is_identifier_string; + exports["parse_js_number"] = parse_js_number; + exports["JS_Parse_Error"] = JS_Parse_Error; + exports["js_error"] = js_error; + exports["is_token"] = is_token; + exports["EX_EOF"] = EX_EOF; + exports["tokenizer"] = tokenizer; + exports["UNARY_PREFIX"] = UNARY_PREFIX; + exports["UNARY_POSTFIX"] = UNARY_POSTFIX; + exports["ASSIGNMENT"] = ASSIGNMENT; + exports["PRECEDENCE"] = PRECEDENCE; + exports["STATEMENTS_WITH_LABELS"] = STATEMENTS_WITH_LABELS; + exports["ATOMIC_START_TOKEN"] = ATOMIC_START_TOKEN; + exports["parse"] = parse; + exports["TreeTransformer"] = TreeTransformer; + exports["SymbolDef"] = SymbolDef; + exports["base54"] = base54; + exports["OutputStream"] = OutputStream; + exports["Compressor"] = Compressor; + exports["SourceMap"] = SourceMap; +})({}, function() { + return exports; +}()); + +var UglifyJS = exports.UglifyJS; + +UglifyJS.AST_Node.warn_function = function(txt) { + logger.error("uglifyjs2 WARN: " + txt); +}; + +//JRB: MODIFIED FROM UGLIFY SOURCE +//to take a name for the file, and then set toplevel.filename to be that name. +exports.minify = function(files, options, name) { + options = UglifyJS.defaults(options, { + outSourceMap : null, + sourceRoot : null, + inSourceMap : null, + fromString : false, + warnings : false, + mangle : {}, + output : null, + compress : {} + }); + if (typeof files == "string") + files = [ files ]; + + UglifyJS.base54.reset(); + + // 1. parse + var toplevel = null; + files.forEach(function(file){ + var code = options.fromString + ? file + : rjsFile.readFile(file, "utf8"); + toplevel = UglifyJS.parse(code, { + filename: options.fromString ? name : file, + toplevel: toplevel + }); + }); + + // 2. compress + if (options.compress) { + var compress = { warnings: options.warnings }; + UglifyJS.merge(compress, options.compress); + toplevel.figure_out_scope(); + var sq = UglifyJS.Compressor(compress); + toplevel = toplevel.transform(sq); + } + + // 3. mangle + if (options.mangle) { + toplevel.figure_out_scope(); + toplevel.compute_char_frequency(); + toplevel.mangle_names(options.mangle); + } + + // 4. output + var inMap = options.inSourceMap; + var output = {}; + if (typeof options.inSourceMap == "string") { + inMap = rjsFile.readFile(options.inSourceMap, "utf8"); + } + if (options.outSourceMap) { + output.source_map = UglifyJS.SourceMap({ + file: options.outSourceMap, + orig: inMap, + root: options.sourceRoot + }); + } + if (options.output) { + UglifyJS.merge(output, options.output); + } + var stream = UglifyJS.OutputStream(output); + toplevel.print(stream); + return { + code : stream + "", + map : output.source_map + "" + }; +}; + +// exports.describe_ast = function() { +// function doitem(ctor) { +// var sub = {}; +// ctor.SUBCLASSES.forEach(function(ctor){ +// sub[ctor.TYPE] = doitem(ctor); +// }); +// var ret = {}; +// if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS; +// if (ctor.SUBCLASSES.length > 0) ret.sub = sub; +// return ret; +// } +// return doitem(UglifyJS.AST_Node).sub; +// } + +exports.describe_ast = function() { + var out = UglifyJS.OutputStream({ beautify: true }); + function doitem(ctor) { + out.print("AST_" + ctor.TYPE); + var props = ctor.SELF_PROPS.filter(function(prop){ + return !/^\$/.test(prop); + }); + if (props.length > 0) { + out.space(); + out.with_parens(function(){ + props.forEach(function(prop, i){ + if (i) out.space(); + out.print(prop); + }); + }); + } + if (ctor.documentation) { + out.space(); + out.print_string(ctor.documentation); + } + if (ctor.SUBCLASSES.length > 0) { + out.space(); + out.with_block(function(){ + ctor.SUBCLASSES.forEach(function(ctor, i){ + out.indent(); + doitem(ctor); + out.newline(); + }); + }); + } + }; + doitem(UglifyJS.AST_Node); + return out + ""; +}; + +}); +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint plusplus: true */ +/*global define: false */ + +define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { + 'use strict'; + + function arrayToString(ary) { + var output = '['; + if (ary) { + ary.forEach(function (item, i) { + output += (i > 0 ? ',' : '') + '"' + lang.jsEscape(item) + '"'; + }); + } + output += ']'; + + return output; + } + + //This string is saved off because JSLint complains + //about obj.arguments use, as 'reserved word' + var argPropName = 'arguments'; + + //From an esprima example for traversing its ast. + function traverse(object, visitor) { + var key, child; + + if (!object) { + return; + } + + if (visitor.call(null, object) === false) { + return false; + } + for (key in object) { + if (object.hasOwnProperty(key)) { + child = object[key]; + if (typeof child === 'object' && child !== null) { + if (traverse(child, visitor) === false) { + return false; + } + } + } + } + } + + //Like traverse, but visitor returning false just + //stops that subtree analysis, not the rest of tree + //visiting. + function traverseBroad(object, visitor) { + var key, child; + + if (!object) { + return; + } + + if (visitor.call(null, object) === false) { + return false; + } + for (key in object) { + if (object.hasOwnProperty(key)) { + child = object[key]; + if (typeof child === 'object' && child !== null) { + traverse(child, visitor); + } + } + } + } + + /** + * Pulls out dependencies from an array literal with just string members. + * If string literals, will just return those string values in an array, + * skipping other items in the array. + * + * @param {Node} node an AST node. + * + * @returns {Array} an array of strings. + * If null is returned, then it means the input node was not a valid + * dependency. + */ + function getValidDeps(node) { + if (!node || node.type !== 'ArrayExpression' || !node.elements) { + return; + } + + var deps = []; + + node.elements.some(function (elem) { + if (elem.type === 'Literal') { + deps.push(elem.value); + } + }); + + return deps.length ? deps : undefined; + } + + /** + * Main parse function. Returns a string of any valid require or + * define/require.def calls as part of one JavaScript source string. + * @param {String} moduleName the module name that represents this file. + * It is used to create a default define if there is not one already for the + * file. This allows properly tracing dependencies for builds. Otherwise, if + * the file just has a require() call, the file dependencies will not be + * properly reflected: the file will come before its dependencies. + * @param {String} moduleName + * @param {String} fileName + * @param {String} fileContents + * @param {Object} options optional options. insertNeedsDefine: true will + * add calls to require.needsDefine() if appropriate. + * @returns {String} JS source string or null, if no require or + * define/require.def calls are found. + */ + function parse(moduleName, fileName, fileContents, options) { + options = options || {}; + + //Set up source input + var i, moduleCall, depString, + moduleDeps = [], + result = '', + moduleList = [], + needsDefine = true, + astRoot = esprima.parse(fileContents); + + parse.recurse(astRoot, function (callName, config, name, deps) { + if (!deps) { + deps = []; + } + + if (callName === 'define' && (!name || name === moduleName)) { + needsDefine = false; + } + + if (!name) { + //If there is no module name, the dependencies are for + //this file/default module name. + moduleDeps = moduleDeps.concat(deps); + } else { + moduleList.push({ + name: name, + deps: deps + }); + } + + //If define was found, no need to dive deeper, unless + //the config explicitly wants to dig deeper. + return !!options.findNestedDependencies; + }, options); + + if (options.insertNeedsDefine && needsDefine) { + result += 'require.needsDefine("' + moduleName + '");'; + } + + if (moduleDeps.length || moduleList.length) { + for (i = 0; i < moduleList.length; i++) { + moduleCall = moduleList[i]; + if (result) { + result += '\n'; + } + + //If this is the main module for this file, combine any + //"anonymous" dependencies (could come from a nested require + //call) with this module. + if (moduleCall.name === moduleName) { + moduleCall.deps = moduleCall.deps.concat(moduleDeps); + moduleDeps = []; + } + + depString = arrayToString(moduleCall.deps); + result += 'define("' + moduleCall.name + '",' + + depString + ');'; + } + if (moduleDeps.length) { + if (result) { + result += '\n'; + } + depString = arrayToString(moduleDeps); + result += 'define("' + moduleName + '",' + depString + ');'; + } + } + + return result || null; + } + + parse.traverse = traverse; + parse.traverseBroad = traverseBroad; + + /** + * Handles parsing a file recursively for require calls. + * @param {Array} parentNode the AST node to start with. + * @param {Function} onMatch function to call on a parse match. + * @param {Object} [options] This is normally the build config options if + * it is passed. + */ + parse.recurse = function (object, onMatch, options) { + //Like traverse, but skips if branches that would not be processed + //after has application that results in tests of true or false boolean + //literal values. + var key, child, + hasHas = options && options.has; + + if (!object) { + return; + } + + //If has replacement has resulted in if(true){} or if(false){}, take + //the appropriate branch and skip the other one. + if (hasHas && object.type === 'IfStatement' && object.test.type && + object.test.type === 'Literal') { + if (object.test.value) { + //Take the if branch + this.recurse(object.consequent, onMatch, options); + } else { + //Take the else branch + this.recurse(object.alternate, onMatch, options); + } + } else { + if (this.parseNode(object, onMatch) === false) { + return; + } + for (key in object) { + if (object.hasOwnProperty(key)) { + child = object[key]; + if (typeof child === 'object' && child !== null) { + this.recurse(child, onMatch, options); + } + } + } + } + }; + + /** + * Determines if the file defines the require/define module API. + * Specifically, it looks for the `define.amd = ` expression. + * @param {String} fileName + * @param {String} fileContents + * @returns {Boolean} + */ + parse.definesRequire = function (fileName, fileContents) { + var found = false; + + traverse(esprima.parse(fileContents), function (node) { + if (parse.hasDefineAmd(node)) { + found = true; + + //Stop traversal + return false; + } + }); + + return found; + }; + + /** + * Finds require("") calls inside a CommonJS anonymous module wrapped in a + * define(function(require, exports, module){}) wrapper. These dependencies + * will be added to a modified define() call that lists the dependencies + * on the outside of the function. + * @param {String} fileName + * @param {String|Object} fileContents: a string of contents, or an already + * parsed AST tree. + * @returns {Array} an array of module names that are dependencies. Always + * returns an array, but could be of length zero. + */ + parse.getAnonDeps = function (fileName, fileContents) { + var astRoot = typeof fileContents === 'string' ? + esprima.parse(fileContents) : fileContents, + defFunc = this.findAnonDefineFactory(astRoot); + + return parse.getAnonDepsFromNode(defFunc); + }; + + /** + * Finds require("") calls inside a CommonJS anonymous module wrapped + * in a define function, given an AST node for the definition function. + * @param {Node} node the AST node for the definition function. + * @returns {Array} and array of dependency names. Can be of zero length. + */ + parse.getAnonDepsFromNode = function (node) { + var deps = [], + funcArgLength; + + if (node) { + this.findRequireDepNames(node, deps); + + //If no deps, still add the standard CommonJS require, exports, + //module, in that order, to the deps, but only if specified as + //function args. In particular, if exports is used, it is favored + //over the return value of the function, so only add it if asked. + funcArgLength = node.params && node.params.length; + if (funcArgLength) { + deps = (funcArgLength > 1 ? ["require", "exports", "module"] : + ["require"]).concat(deps); + } + } + return deps; + }; + + parse.isDefineNodeWithArgs = function (node) { + return node && node.type === 'CallExpression' && + node.callee && node.callee.type === 'Identifier' && + node.callee.name === 'define' && node[argPropName]; + }; + + /** + * Finds the function in define(function (require, exports, module){}); + * @param {Array} node + * @returns {Boolean} + */ + parse.findAnonDefineFactory = function (node) { + var match; + + traverse(node, function (node) { + var arg0, arg1; + + if (parse.isDefineNodeWithArgs(node)) { + + //Just the factory function passed to define + arg0 = node[argPropName][0]; + if (arg0 && arg0.type === 'FunctionExpression') { + match = arg0; + return false; + } + + //A string literal module ID followed by the factory function. + arg1 = node[argPropName][1]; + if (arg0.type === 'Literal' && + arg1 && arg1.type === 'FunctionExpression') { + match = arg1; + return false; + } + } + }); + + return match; + }; + + /** + * Finds any config that is passed to requirejs. That includes calls to + * require/requirejs.config(), as well as require({}, ...) and + * requirejs({}, ...) + * @param {String} fileContents + * + * @returns {Object} a config details object with the following properties: + * - config: {Object} the config object found. Can be undefined if no + * config found. + * - range: {Array} the start index and end index in the contents where + * the config was found. Can be undefined if no config found. + * Can throw an error if the config in the file cannot be evaluated in + * a build context to valid JavaScript. + */ + parse.findConfig = function (fileContents) { + /*jslint evil: true */ + var jsConfig, foundConfig, stringData, foundRange, quote, quoteMatch, + quoteRegExp = /(:\s|\[\s*)(['"])/, + astRoot = esprima.parse(fileContents, { + loc: true + }); + + traverse(astRoot, function (node) { + var arg, + requireType = parse.hasRequire(node); + + if (requireType && (requireType === 'require' || + requireType === 'requirejs' || + requireType === 'requireConfig' || + requireType === 'requirejsConfig')) { + + arg = node[argPropName] && node[argPropName][0]; + + if (arg && arg.type === 'ObjectExpression') { + stringData = parse.nodeToString(fileContents, arg); + jsConfig = stringData.value; + foundRange = stringData.range; + return false; + } + } else { + arg = parse.getRequireObjectLiteral(node); + if (arg) { + stringData = parse.nodeToString(fileContents, arg); + jsConfig = stringData.value; + foundRange = stringData.range; + return false; + } + } + }); + + if (jsConfig) { + // Eval the config + quoteMatch = quoteRegExp.exec(jsConfig); + quote = (quoteMatch && quoteMatch[2]) || '"'; + foundConfig = eval('(' + jsConfig + ')'); + } + + return { + config: foundConfig, + range: foundRange, + quote: quote + }; + }; + + /** Returns the node for the object literal assigned to require/requirejs, + * for holding a declarative config. + */ + parse.getRequireObjectLiteral = function (node) { + if (node.id && node.id.type === 'Identifier' && + (node.id.name === 'require' || node.id.name === 'requirejs') && + node.init && node.init.type === 'ObjectExpression') { + return node.init; + } + }; + + /** + * Renames require/requirejs/define calls to be ns + '.' + require/requirejs/define + * Does *not* do .config calls though. See pragma.namespace for the complete + * set of namespace transforms. This function is used because require calls + * inside a define() call should not be renamed, so a simple regexp is not + * good enough. + * @param {String} fileContents the contents to transform. + * @param {String} ns the namespace, *not* including trailing dot. + * @return {String} the fileContents with the namespace applied + */ + parse.renameNamespace = function (fileContents, ns) { + var lines, + locs = [], + astRoot = esprima.parse(fileContents, { + loc: true + }); + + parse.recurse(astRoot, function (callName, config, name, deps, node) { + locs.push(node.loc); + //Do not recurse into define functions, they should be using + //local defines. + return callName !== 'define'; + }, {}); + + if (locs.length) { + lines = fileContents.split('\n'); + + //Go backwards through the found locs, adding in the namespace name + //in front. + locs.reverse(); + locs.forEach(function (loc) { + var startIndex = loc.start.column, + //start.line is 1-based, not 0 based. + lineIndex = loc.start.line - 1, + line = lines[lineIndex]; + + lines[lineIndex] = line.substring(0, startIndex) + + ns + '.' + + line.substring(startIndex, + line.length); + }); + + fileContents = lines.join('\n'); + } + + return fileContents; + }; + + /** + * Finds all dependencies specified in dependency arrays and inside + * simplified commonjs wrappers. + * @param {String} fileName + * @param {String} fileContents + * + * @returns {Array} an array of dependency strings. The dependencies + * have not been normalized, they may be relative IDs. + */ + parse.findDependencies = function (fileName, fileContents, options) { + var dependencies = [], + astRoot = esprima.parse(fileContents); + + parse.recurse(astRoot, function (callName, config, name, deps) { + if (deps) { + dependencies = dependencies.concat(deps); + } + }, options); + + return dependencies; + }; + + /** + * Finds only CJS dependencies, ones that are the form + * require('stringLiteral') + */ + parse.findCjsDependencies = function (fileName, fileContents) { + var dependencies = []; + + traverse(esprima.parse(fileContents), function (node) { + var arg; + + if (node && node.type === 'CallExpression' && node.callee && + node.callee.type === 'Identifier' && + node.callee.name === 'require' && node[argPropName] && + node[argPropName].length === 1) { + arg = node[argPropName][0]; + if (arg.type === 'Literal') { + dependencies.push(arg.value); + } + } + }); + + return dependencies; + }; + + //function define() {} + parse.hasDefDefine = function (node) { + return node.type === 'FunctionDeclaration' && node.id && + node.id.type === 'Identifier' && node.id.name === 'define'; + }; + + //define.amd = ... + parse.hasDefineAmd = function (node) { + return node && node.type === 'AssignmentExpression' && + node.left && node.left.type === 'MemberExpression' && + node.left.object && node.left.object.name === 'define' && + node.left.property && node.left.property.name === 'amd'; + }; + + //define.amd reference, as in: if (define.amd) + parse.refsDefineAmd = function (node) { + return node && node.type === 'MemberExpression' && + node.object && node.object.name === 'define' && + node.object.type === 'Identifier' && + node.property && node.property.name === 'amd' && + node.property.type === 'Identifier'; + }; + + //require(), requirejs(), require.config() and requirejs.config() + parse.hasRequire = function (node) { + var callName, + c = node && node.callee; + + if (node && node.type === 'CallExpression' && c) { + if (c.type === 'Identifier' && + (c.name === 'require' || + c.name === 'requirejs')) { + //A require/requirejs({}, ...) call + callName = c.name; + } else if (c.type === 'MemberExpression' && + c.object && + c.object.type === 'Identifier' && + (c.object.name === 'require' || + c.object.name === 'requirejs') && + c.property && c.property.name === 'config') { + // require/requirejs.config({}) call + callName = c.object.name + 'Config'; + } + } + + return callName; + }; + + //define() + parse.hasDefine = function (node) { + return node && node.type === 'CallExpression' && node.callee && + node.callee.type === 'Identifier' && + node.callee.name === 'define'; + }; + + /** + * If there is a named define in the file, returns the name. Does not + * scan for mulitple names, just the first one. + */ + parse.getNamedDefine = function (fileContents) { + var name; + traverse(esprima.parse(fileContents), function (node) { + if (node && node.type === 'CallExpression' && node.callee && + node.callee.type === 'Identifier' && + node.callee.name === 'define' && + node[argPropName] && node[argPropName][0] && + node[argPropName][0].type === 'Literal') { + name = node[argPropName][0].value; + return false; + } + }); + + return name; + }; + + /** + * Determines if define(), require({}|[]) or requirejs was called in the + * file. Also finds out if define() is declared and if define.amd is called. + */ + parse.usesAmdOrRequireJs = function (fileName, fileContents) { + var uses; + + traverse(esprima.parse(fileContents), function (node) { + var type, callName, arg; + + if (parse.hasDefDefine(node)) { + //function define() {} + type = 'declaresDefine'; + } else if (parse.hasDefineAmd(node)) { + type = 'defineAmd'; + } else { + callName = parse.hasRequire(node); + if (callName) { + arg = node[argPropName] && node[argPropName][0]; + if (arg && (arg.type === 'ObjectExpression' || + arg.type === 'ArrayExpression')) { + type = callName; + } + } else if (parse.hasDefine(node)) { + type = 'define'; + } + } + + if (type) { + if (!uses) { + uses = {}; + } + uses[type] = true; + } + }); + + return uses; + }; + + /** + * Determines if require(''), exports.x =, module.exports =, + * __dirname, __filename are used. So, not strictly traditional CommonJS, + * also checks for Node variants. + */ + parse.usesCommonJs = function (fileName, fileContents) { + var uses = null, + assignsExports = false; + + + traverse(esprima.parse(fileContents), function (node) { + var type, + exp = node.expression || node.init; + + if (node.type === 'Identifier' && + (node.name === '__dirname' || node.name === '__filename')) { + type = node.name.substring(2); + } else if (node.type === 'VariableDeclarator' && node.id && + node.id.type === 'Identifier' && + node.id.name === 'exports') { + //Hmm, a variable assignment for exports, so does not use cjs + //exports. + type = 'varExports'; + } else if (exp && exp.type === 'AssignmentExpression' && exp.left && + exp.left.type === 'MemberExpression' && exp.left.object) { + if (exp.left.object.name === 'module' && exp.left.property && + exp.left.property.name === 'exports') { + type = 'moduleExports'; + } else if (exp.left.object.name === 'exports' && + exp.left.property) { + type = 'exports'; + } + + } else if (node && node.type === 'CallExpression' && node.callee && + node.callee.type === 'Identifier' && + node.callee.name === 'require' && node[argPropName] && + node[argPropName].length === 1 && + node[argPropName][0].type === 'Literal') { + type = 'require'; + } + + if (type) { + if (type === 'varExports') { + assignsExports = true; + } else if (type !== 'exports' || !assignsExports) { + if (!uses) { + uses = {}; + } + uses[type] = true; + } + } + }); + + return uses; + }; + + + parse.findRequireDepNames = function (node, deps) { + traverse(node, function (node) { + var arg; + + if (node && node.type === 'CallExpression' && node.callee && + node.callee.type === 'Identifier' && + node.callee.name === 'require' && + node[argPropName] && node[argPropName].length === 1) { + + arg = node[argPropName][0]; + if (arg.type === 'Literal') { + deps.push(arg.value); + } + } + }); + }; + + /** + * Determines if a specific node is a valid require or define/require.def + * call. + * @param {Array} node + * @param {Function} onMatch a function to call when a match is found. + * It is passed the match name, and the config, name, deps possible args. + * The config, name and deps args are not normalized. + * + * @returns {String} a JS source string with the valid require/define call. + * Otherwise null. + */ + parse.parseNode = function (node, onMatch) { + var name, deps, cjsDeps, arg, factory, exp, refsDefine, bodyNode, + args = node && node[argPropName], + callName = parse.hasRequire(node); + + if (callName === 'require' || callName === 'requirejs') { + //A plain require/requirejs call + arg = node[argPropName] && node[argPropName][0]; + if (arg.type !== 'ArrayExpression') { + if (arg.type === 'ObjectExpression') { + //A config call, try the second arg. + arg = node[argPropName][1]; + } + } + + deps = getValidDeps(arg); + if (!deps) { + return; + } + + return onMatch("require", null, null, deps, node); + } else if (parse.hasDefine(node) && args && args.length) { + name = args[0]; + deps = args[1]; + factory = args[2]; + + if (name.type === 'ArrayExpression') { + //No name, adjust args + factory = deps; + deps = name; + name = null; + } else if (name.type === 'FunctionExpression') { + //Just the factory, no name or deps + factory = name; + name = deps = null; + } else if (name.type !== 'Literal') { + //An object literal, just null out + name = deps = factory = null; + } + + if (name && name.type === 'Literal' && deps) { + if (deps.type === 'FunctionExpression') { + //deps is the factory + factory = deps; + deps = null; + } else if (deps.type === 'ObjectExpression') { + //deps is object literal, null out + deps = factory = null; + } else if (deps.type === 'Identifier' && args.length === 2) { + // define('id', factory) + deps = factory = null; + } + } + + if (deps && deps.type === 'ArrayExpression') { + deps = getValidDeps(deps); + } else if (factory && factory.type === 'FunctionExpression') { + //If no deps and a factory function, could be a commonjs sugar + //wrapper, scan the function for dependencies. + cjsDeps = parse.getAnonDepsFromNode(factory); + if (cjsDeps.length) { + deps = cjsDeps; + } + } else if (deps || factory) { + //Does not match the shape of an AMD call. + return; + } + + //Just save off the name as a string instead of an AST object. + if (name && name.type === 'Literal') { + name = name.value; + } + + return onMatch("define", null, name, deps, node); + } else if (node.type === 'CallExpression' && node.callee && + node.callee.type === 'FunctionExpression' && + node.callee.body && node.callee.body.body && + node.callee.body.body.length === 1 && + node.callee.body.body[0].type === 'IfStatement') { + bodyNode = node.callee.body.body[0]; + //Look for a define(Identifier) case, but only if inside an + //if that has a define.amd test + if (bodyNode.consequent && bodyNode.consequent.body) { + exp = bodyNode.consequent.body[0]; + if (exp.type === 'ExpressionStatement' && exp.expression && + parse.hasDefine(exp.expression) && + exp.expression.arguments && + exp.expression.arguments.length === 1 && + exp.expression.arguments[0].type === 'Identifier') { + + //Calls define(Identifier) as first statement in body. + //Confirm the if test references define.amd + traverse(bodyNode.test, function (node) { + if (parse.refsDefineAmd(node)) { + refsDefine = true; + return false; + } + }); + + if (refsDefine) { + return onMatch("define", null, null, null, exp.expression); + } + } + } + } + }; + + /** + * Converts an AST node into a JS source string by extracting + * the node's location from the given contents string. Assumes + * esprima.parse() with loc was done. + * @param {String} contents + * @param {Object} node + * @returns {String} a JS source string. + */ + parse.nodeToString = function (contents, node) { + var extracted, + loc = node.loc, + lines = contents.split('\n'), + firstLine = loc.start.line > 1 ? + lines.slice(0, loc.start.line - 1).join('\n') + '\n' : + '', + preamble = firstLine + + lines[loc.start.line - 1].substring(0, loc.start.column); + + if (loc.start.line === loc.end.line) { + extracted = lines[loc.start.line - 1].substring(loc.start.column, + loc.end.column); + } else { + extracted = lines[loc.start.line - 1].substring(loc.start.column) + + '\n' + + lines.slice(loc.start.line, loc.end.line - 1).join('\n') + + '\n' + + lines[loc.end.line - 1].substring(0, loc.end.column); + } + + return { + value: extracted, + range: [ + preamble.length, + preamble.length + extracted.length + ] + }; + }; + + /** + * Extracts license comments from JS text. + * @param {String} fileName + * @param {String} contents + * @returns {String} a string of license comments. + */ + parse.getLicenseComments = function (fileName, contents) { + var commentNode, refNode, subNode, value, i, j, + //xpconnect's Reflect does not support comment or range, but + //prefer continued operation vs strict parity of operation, + //as license comments can be expressed in other ways, like + //via wrap args, or linked via sourcemaps. + ast = esprima.parse(contents, { + comment: true, + range: true + }), + result = '', + existsMap = {}, + lineEnd = contents.indexOf('\r') === -1 ? '\n' : '\r\n'; + + if (ast.comments) { + for (i = 0; i < ast.comments.length; i++) { + commentNode = ast.comments[i]; + + if (commentNode.type === 'Line') { + value = '//' + commentNode.value + lineEnd; + refNode = commentNode; + + if (i + 1 >= ast.comments.length) { + value += lineEnd; + } else { + //Look for immediately adjacent single line comments + //since it could from a multiple line comment made out + //of single line comments. Like this comment. + for (j = i + 1; j < ast.comments.length; j++) { + subNode = ast.comments[j]; + if (subNode.type === 'Line' && + subNode.range[0] === refNode.range[1] + 1) { + //Adjacent single line comment. Collect it. + value += '//' + subNode.value + lineEnd; + refNode = subNode; + } else { + //No more single line comment blocks. Break out + //and continue outer looping. + break; + } + } + value += lineEnd; + i = j - 1; + } + } else { + value = '/*' + commentNode.value + '*/' + lineEnd + lineEnd; + } + + if (!existsMap[value] && (value.indexOf('license') !== -1 || + (commentNode.type === 'Block' && + value.indexOf('/*!') === 0) || + value.indexOf('opyright') !== -1 || + value.indexOf('(c)') !== -1)) { + + result += value; + existsMap[value] = true; + } + + } + } + + return result; + }; + + return parse; +}); +/** + * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*global define */ + +define('transform', [ './esprimaAdapter', './parse', 'logger', 'lang'], +function (esprima, parse, logger, lang) { + 'use strict'; + var transform, + baseIndentRegExp = /^([ \t]+)/, + indentRegExp = /\{[\r\n]+([ \t]+)/, + keyRegExp = /^[_A-Za-z]([A-Za-z\d_]*)$/, + bulkIndentRegExps = { + '\n': /\n/g, + '\r\n': /\r\n/g + }; + + function applyIndent(str, indent, lineReturn) { + var regExp = bulkIndentRegExps[lineReturn]; + return str.replace(regExp, '$&' + indent); + } + + transform = { + toTransport: function (namespace, moduleName, path, contents, onFound, options) { + options = options || {}; + + var astRoot, contentLines, modLine, + foundAnon, + scanCount = 0, + scanReset = false, + defineInfos = []; + + try { + astRoot = esprima.parse(contents, { + loc: true + }); + } catch (e) { + logger.trace('toTransport skipping ' + path + ': ' + + e.toString()); + return contents; + } + + //Find the define calls and their position in the files. + parse.traverseBroad(astRoot, function (node) { + var args, firstArg, firstArgLoc, factoryNode, + needsId, depAction, foundId, + sourceUrlData, range, + namespaceExists = false; + + namespaceExists = namespace && + node.type === 'CallExpression' && + node.callee && node.callee.object && + node.callee.object.type === 'Identifier' && + node.callee.object.name === namespace && + node.callee.property.type === 'Identifier' && + node.callee.property.name === 'define'; + + if (namespaceExists || parse.isDefineNodeWithArgs(node)) { + //The arguments are where its at. + args = node.arguments; + if (!args || !args.length) { + return; + } + + firstArg = args[0]; + firstArgLoc = firstArg.loc; + + if (args.length === 1) { + if (firstArg.type === 'Identifier') { + //The define(factory) case, but + //only allow it if one Identifier arg, + //to limit impact of false positives. + needsId = true; + depAction = 'empty'; + } else if (firstArg.type === 'FunctionExpression') { + //define(function(){}) + factoryNode = firstArg; + needsId = true; + depAction = 'scan'; + } else if (firstArg.type === 'ObjectExpression') { + //define({}); + needsId = true; + depAction = 'skip'; + } else if (firstArg.type === 'Literal' && + typeof firstArg.value === 'number') { + //define('12345'); + needsId = true; + depAction = 'skip'; + } else if (firstArg.type === 'UnaryExpression' && + firstArg.operator === '-' && + firstArg.argument && + firstArg.argument.type === 'Literal' && + typeof firstArg.argument.value === 'number') { + //define('-12345'); + needsId = true; + depAction = 'skip'; + } else if (firstArg.type === 'MemberExpression' && + firstArg.object && + firstArg.property && + firstArg.property.type === 'Identifier') { + //define(this.key); + needsId = true; + depAction = 'empty'; + } + } else if (firstArg.type === 'ArrayExpression') { + //define([], ...); + needsId = true; + depAction = 'skip'; + } else if (firstArg.type === 'Literal' && + typeof firstArg.value === 'string') { + //define('string', ....) + //Already has an ID. + needsId = false; + if (args.length === 2 && + args[1].type === 'FunctionExpression') { + //Needs dependency scanning. + factoryNode = args[1]; + depAction = 'scan'; + } else { + depAction = 'skip'; + } + } else { + //Unknown define entity, keep looking, even + //in the subtree for this node. + return; + } + + range = { + foundId: foundId, + needsId: needsId, + depAction: depAction, + namespaceExists: namespaceExists, + node: node, + defineLoc: node.loc, + firstArgLoc: firstArgLoc, + factoryNode: factoryNode, + sourceUrlData: sourceUrlData + }; + + //Only transform ones that do not have IDs. If it has an + //ID but no dependency array, assume it is something like + //a phonegap implementation, that has its own internal + //define that cannot handle dependency array constructs, + //and if it is a named module, then it means it has been + //set for transport form. + if (range.needsId) { + if (foundAnon) { + logger.trace(path + ' has more than one anonymous ' + + 'define. May be a built file from another ' + + 'build system like, Ender. Skipping normalization.'); + defineInfos = []; + return false; + } else { + foundAnon = range; + defineInfos.push(range); + } + } else if (depAction === 'scan') { + scanCount += 1; + if (scanCount > 1) { + //Just go back to an array that just has the + //anon one, since this is an already optimized + //file like the phonegap one. + if (!scanReset) { + defineInfos = foundAnon ? [foundAnon] : []; + scanReset = true; + } + } else { + defineInfos.push(range); + } + } + } + }); + + if (!defineInfos.length) { + return contents; + } + + //Reverse the matches, need to start from the bottom of + //the file to modify it, so that the ranges are still true + //further up. + defineInfos.reverse(); + + contentLines = contents.split('\n'); + + modLine = function (loc, contentInsertion) { + var startIndex = loc.start.column, + //start.line is 1-based, not 0 based. + lineIndex = loc.start.line - 1, + line = contentLines[lineIndex]; + contentLines[lineIndex] = line.substring(0, startIndex) + + contentInsertion + + line.substring(startIndex, + line.length); + }; + + defineInfos.forEach(function (info) { + var deps, + contentInsertion = '', + depString = ''; + + //Do the modifications "backwards", in other words, start with the + //one that is farthest down and work up, so that the ranges in the + //defineInfos still apply. So that means deps, id, then namespace. + if (info.needsId && moduleName) { + contentInsertion += "'" + moduleName + "',"; + } + + if (info.depAction === 'scan') { + deps = parse.getAnonDepsFromNode(info.factoryNode); + + if (deps.length) { + depString = '[' + deps.map(function (dep) { + return "'" + dep + "'"; + }) + ']'; + } else { + depString = '[]'; + } + depString += ','; + + if (info.factoryNode) { + //Already have a named module, need to insert the + //dependencies after the name. + modLine(info.factoryNode.loc, depString); + } else { + contentInsertion += depString; + } + } + + if (contentInsertion) { + modLine(info.firstArgLoc, contentInsertion); + } + + //Do namespace last so that ui does not mess upthe parenRange + //used above. + if (namespace && !info.namespaceExists) { + modLine(info.defineLoc, namespace + '.'); + } + + //Notify any listener for the found info + if (onFound) { + onFound(info); + } + }); + + contents = contentLines.join('\n'); + + if (options.useSourceUrl) { + contents = 'eval("' + lang.jsEscape(contents) + + '\\n//# sourceURL=' + (path.indexOf('/') === 0 ? '' : '/') + + path + + '");\n'; + } + + return contents; + }, + + /** + * Modify the contents of a require.config/requirejs.config call. This + * call will LOSE any existing comments that are in the config string. + * + * @param {String} fileContents String that may contain a config call + * @param {Function} onConfig Function called when the first config + * call is found. It will be passed an Object which is the current + * config, and the onConfig function should return an Object to use + * as the config. + * @return {String} the fileContents with the config changes applied. + */ + modifyConfig: function (fileContents, onConfig) { + var details = parse.findConfig(fileContents), + config = details.config; + + if (config) { + config = onConfig(config); + if (config) { + return transform.serializeConfig(config, + fileContents, + details.range[0], + details.range[1], + { + quote: details.quote + }); + } + } + + return fileContents; + }, + + serializeConfig: function (config, fileContents, start, end, options) { + //Calculate base level of indent + var indent, match, configString, outDentRegExp, + baseIndent = '', + startString = fileContents.substring(0, start), + existingConfigString = fileContents.substring(start, end), + lineReturn = existingConfigString.indexOf('\r') === -1 ? '\n' : '\r\n', + lastReturnIndex = startString.lastIndexOf('\n'); + + //Get the basic amount of indent for the require config call. + if (lastReturnIndex === -1) { + lastReturnIndex = 0; + } + + match = baseIndentRegExp.exec(startString.substring(lastReturnIndex + 1, start)); + if (match && match[1]) { + baseIndent = match[1]; + } + + //Calculate internal indentation for config + match = indentRegExp.exec(existingConfigString); + if (match && match[1]) { + indent = match[1]; + } + + if (!indent || indent.length < baseIndent) { + indent = ' '; + } else { + indent = indent.substring(baseIndent.length); + } + + outDentRegExp = new RegExp('(' + lineReturn + ')' + indent, 'g'); + + configString = transform.objectToString(config, { + indent: indent, + lineReturn: lineReturn, + outDentRegExp: outDentRegExp, + quote: options && options.quote + }); + + //Add in the base indenting level. + configString = applyIndent(configString, baseIndent, lineReturn); + + return startString + configString + fileContents.substring(end); + }, + + /** + * Tries converting a JS object to a string. This will likely suck, and + * is tailored to the type of config expected in a loader config call. + * So, hasOwnProperty fields, strings, numbers, arrays and functions, + * no weird recursively referenced stuff. + * @param {Object} obj the object to convert + * @param {Object} options options object with the following values: + * {String} indent the indentation to use for each level + * {String} lineReturn the type of line return to use + * {outDentRegExp} outDentRegExp the regexp to use to outdent functions + * {String} quote the quote type to use, ' or ". Optional. Default is " + * @param {String} totalIndent the total indent to print for this level + * @return {String} a string representation of the object. + */ + objectToString: function (obj, options, totalIndent) { + var startBrace, endBrace, nextIndent, + first = true, + value = '', + lineReturn = options.lineReturn, + indent = options.indent, + outDentRegExp = options.outDentRegExp, + quote = options.quote || '"'; + + totalIndent = totalIndent || ''; + nextIndent = totalIndent + indent; + + if (obj === null) { + value = 'null'; + } else if (obj === undefined) { + value = 'undefined'; + } else if (typeof obj === 'number' || typeof obj === 'boolean') { + value = obj; + } else if (typeof obj === 'string') { + //Use double quotes in case the config may also work as JSON. + value = quote + lang.jsEscape(obj) + quote; + } else if (lang.isArray(obj)) { + lang.each(obj, function (item, i) { + value += (i !== 0 ? ',' + lineReturn : '' ) + + nextIndent + + transform.objectToString(item, + options, + nextIndent); + }); + + startBrace = '['; + endBrace = ']'; + } else if (lang.isFunction(obj) || lang.isRegExp(obj)) { + //The outdent regexp just helps pretty up the conversion + //just in node. Rhino strips comments and does a different + //indent scheme for Function toString, so not really helpful + //there. + value = obj.toString().replace(outDentRegExp, '$1'); + } else { + //An object + lang.eachProp(obj, function (v, prop) { + value += (first ? '': ',' + lineReturn) + + nextIndent + + (keyRegExp.test(prop) ? prop : quote + lang.jsEscape(prop) + quote )+ + ': ' + + transform.objectToString(v, + options, + nextIndent); + first = false; + }); + startBrace = '{'; + endBrace = '}'; + } + + if (startBrace) { + value = startBrace + + lineReturn + + value + + lineReturn + totalIndent + + endBrace; + } + + return value; + } + }; + + return transform; +}); +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint regexp: true, plusplus: true */ +/*global define: false */ + +define('pragma', ['parse', 'logger'], function (parse, logger) { + 'use strict'; + function Temp() {} + + function create(obj, mixin) { + Temp.prototype = obj; + var temp = new Temp(), prop; + + //Avoid any extra memory hanging around + Temp.prototype = null; + + if (mixin) { + for (prop in mixin) { + if (mixin.hasOwnProperty(prop) && !temp.hasOwnProperty(prop)) { + temp[prop] = mixin[prop]; + } + } + } + + return temp; // Object + } + + var pragma = { + conditionalRegExp: /(exclude|include)Start\s*\(\s*["'](\w+)["']\s*,(.*)\)/, + useStrictRegExp: /['"]use strict['"];/g, + hasRegExp: /has\s*\(\s*['"]([^'"]+)['"]\s*\)/g, + configRegExp: /(^|[^\.])(requirejs|require)(\.config)\s*\(/g, + nsWrapRegExp: /\/\*requirejs namespace: true \*\//, + apiDefRegExp: /var requirejs,\s*require,\s*define;/, + defineCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd/g, + defineStringCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\[\s*["']amd["']\s*\]/g, + defineTypeFirstCheckRegExp: /\s*["']function["']\s*==(=?)\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g, + defineJQueryRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd\s*&&\s*define\s*\.\s*amd\s*\.\s*jQuery/g, + defineHasRegExp: /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g, + defineTernaryRegExp: /typeof\s+define\s*===\s*['"]function["']\s*&&\s*define\s*\.\s*amd\s*\?\s*define/, + amdefineRegExp: /if\s*\(\s*typeof define\s*\!==\s*'function'\s*\)\s*\{\s*[^\{\}]+amdefine[^\{\}]+\}/g, + + removeStrict: function (contents, config) { + return config.useStrict ? contents : contents.replace(pragma.useStrictRegExp, ''); + }, + + namespace: function (fileContents, ns, onLifecycleName) { + if (ns) { + //Namespace require/define calls + fileContents = fileContents.replace(pragma.configRegExp, '$1' + ns + '.$2$3('); + + + fileContents = parse.renameNamespace(fileContents, ns); + + //Namespace define ternary use: + fileContents = fileContents.replace(pragma.defineTernaryRegExp, + "typeof " + ns + ".define === 'function' && " + ns + ".define.amd ? " + ns + ".define"); + + //Namespace define jquery use: + fileContents = fileContents.replace(pragma.defineJQueryRegExp, + "typeof " + ns + ".define === 'function' && " + ns + ".define.amd && " + ns + ".define.amd.jQuery"); + + //Namespace has.js define use: + fileContents = fileContents.replace(pragma.defineHasRegExp, + "typeof " + ns + ".define === 'function' && typeof " + ns + ".define.amd === 'object' && " + ns + ".define.amd"); + + //Namespace define checks. + //Do these ones last, since they are a subset of the more specific + //checks above. + fileContents = fileContents.replace(pragma.defineCheckRegExp, + "typeof " + ns + ".define === 'function' && " + ns + ".define.amd"); + fileContents = fileContents.replace(pragma.defineStringCheckRegExp, + "typeof " + ns + ".define === 'function' && " + ns + ".define['amd']"); + fileContents = fileContents.replace(pragma.defineTypeFirstCheckRegExp, + "'function' === typeof " + ns + ".define && " + ns + ".define.amd"); + + //Check for require.js with the require/define definitions + if (pragma.apiDefRegExp.test(fileContents) && + fileContents.indexOf("if (!" + ns + " || !" + ns + ".requirejs)") === -1) { + //Wrap the file contents in a typeof check, and a function + //to contain the API globals. + fileContents = "var " + ns + ";(function () { if (!" + ns + " || !" + ns + ".requirejs) {\n" + + "if (!" + ns + ") { " + ns + ' = {}; } else { require = ' + ns + '; }\n' + + fileContents + + "\n" + + ns + ".requirejs = requirejs;" + + ns + ".require = require;" + + ns + ".define = define;\n" + + "}\n}());"; + } + + //Finally, if the file wants a special wrapper because it ties + //in to the requirejs internals in a way that would not fit + //the above matches, do that. Look for /*requirejs namespace: true*/ + if (pragma.nsWrapRegExp.test(fileContents)) { + //Remove the pragma. + fileContents = fileContents.replace(pragma.nsWrapRegExp, ''); + + //Alter the contents. + fileContents = '(function () {\n' + + 'var require = ' + ns + '.require,' + + 'requirejs = ' + ns + '.requirejs,' + + 'define = ' + ns + '.define;\n' + + fileContents + + '\n}());'; + } + } + + return fileContents; + }, + + /** + * processes the fileContents for some //>> conditional statements + */ + process: function (fileName, fileContents, config, onLifecycleName, pluginCollector) { + /*jslint evil: true */ + var foundIndex = -1, startIndex = 0, lineEndIndex, conditionLine, + matches, type, marker, condition, isTrue, endRegExp, endMatches, + endMarkerIndex, shouldInclude, startLength, lifecycleHas, deps, + i, dep, moduleName, collectorMod, + lifecyclePragmas, pragmas = config.pragmas, hasConfig = config.has, + //Legacy arg defined to help in dojo conversion script. Remove later + //when dojo no longer needs conversion: + kwArgs = pragmas; + + //Mix in a specific lifecycle scoped object, to allow targeting + //some pragmas/has tests to only when files are saved, or at different + //lifecycle events. Do not bother with kwArgs in this section, since + //the old dojo kwArgs were for all points in the build lifecycle. + if (onLifecycleName) { + lifecyclePragmas = config['pragmas' + onLifecycleName]; + lifecycleHas = config['has' + onLifecycleName]; + + if (lifecyclePragmas) { + pragmas = create(pragmas || {}, lifecyclePragmas); + } + + if (lifecycleHas) { + hasConfig = create(hasConfig || {}, lifecycleHas); + } + } + + //Replace has references if desired + if (hasConfig) { + fileContents = fileContents.replace(pragma.hasRegExp, function (match, test) { + if (hasConfig.hasOwnProperty(test)) { + return !!hasConfig[test]; + } + return match; + }); + } + + if (!config.skipPragmas) { + + while ((foundIndex = fileContents.indexOf("//>>", startIndex)) !== -1) { + //Found a conditional. Get the conditional line. + lineEndIndex = fileContents.indexOf("\n", foundIndex); + if (lineEndIndex === -1) { + lineEndIndex = fileContents.length - 1; + } + + //Increment startIndex past the line so the next conditional search can be done. + startIndex = lineEndIndex + 1; + + //Break apart the conditional. + conditionLine = fileContents.substring(foundIndex, lineEndIndex + 1); + matches = conditionLine.match(pragma.conditionalRegExp); + if (matches) { + type = matches[1]; + marker = matches[2]; + condition = matches[3]; + isTrue = false; + //See if the condition is true. + try { + isTrue = !!eval("(" + condition + ")"); + } catch (e) { + throw "Error in file: " + + fileName + + ". Conditional comment: " + + conditionLine + + " failed with this error: " + e; + } + + //Find the endpoint marker. + endRegExp = new RegExp('\\/\\/\\>\\>\\s*' + type + 'End\\(\\s*[\'"]' + marker + '[\'"]\\s*\\)', "g"); + endMatches = endRegExp.exec(fileContents.substring(startIndex, fileContents.length)); + if (endMatches) { + endMarkerIndex = startIndex + endRegExp.lastIndex - endMatches[0].length; + + //Find the next line return based on the match position. + lineEndIndex = fileContents.indexOf("\n", endMarkerIndex); + if (lineEndIndex === -1) { + lineEndIndex = fileContents.length - 1; + } + + //Should we include the segment? + shouldInclude = ((type === "exclude" && !isTrue) || (type === "include" && isTrue)); + + //Remove the conditional comments, and optionally remove the content inside + //the conditional comments. + startLength = startIndex - foundIndex; + fileContents = fileContents.substring(0, foundIndex) + + (shouldInclude ? fileContents.substring(startIndex, endMarkerIndex) : "") + + fileContents.substring(lineEndIndex + 1, fileContents.length); + + //Move startIndex to foundIndex, since that is the new position in the file + //where we need to look for more conditionals in the next while loop pass. + startIndex = foundIndex; + } else { + throw "Error in file: " + + fileName + + ". Cannot find end marker for conditional comment: " + + conditionLine; + + } + } + } + } + + //If need to find all plugin resources to optimize, do that now, + //before namespacing, since the namespacing will change the API + //names. + //If there is a plugin collector, scan the file for plugin resources. + if (config.optimizeAllPluginResources && pluginCollector) { + try { + deps = parse.findDependencies(fileName, fileContents); + if (deps.length) { + for (i = 0; i < deps.length; i++) { + dep = deps[i]; + if (dep.indexOf('!') !== -1) { + moduleName = dep.split('!')[0]; + collectorMod = pluginCollector[moduleName]; + if (!collectorMod) { + collectorMod = pluginCollector[moduleName] = []; + } + collectorMod.push(dep); + } + } + } + } catch (eDep) { + logger.error('Parse error looking for plugin resources in ' + + fileName + ', skipping.'); + } + } + + //Strip amdefine use for node-shared modules. + fileContents = fileContents.replace(pragma.amdefineRegExp, ''); + + //Do namespacing + if (onLifecycleName === 'OnSave' && config.namespace) { + fileContents = pragma.namespace(fileContents, config.namespace, onLifecycleName); + } + + + return pragma.removeStrict(fileContents, config); + } + }; + + return pragma; +}); +if(env === 'browser') { +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false */ + +define('browser/optimize', {}); + +} + +if(env === 'node') { +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint strict: false */ +/*global define: false */ + +define('node/optimize', {}); + +} + +if(env === 'rhino') { +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint sloppy: true, plusplus: true */ +/*global define, java, Packages, com */ + +define('rhino/optimize', ['logger', 'env!env/file'], function (logger, file) { + + //Add .reduce to Rhino so UglifyJS can run in Rhino, + //inspired by https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce + //but rewritten for brevity, and to be good enough for use by UglifyJS. + if (!Array.prototype.reduce) { + Array.prototype.reduce = function (fn /*, initialValue */) { + var i = 0, + length = this.length, + accumulator; + + if (arguments.length >= 2) { + accumulator = arguments[1]; + } else { + if (length) { + while (!(i in this)) { + i++; + } + accumulator = this[i++]; + } + } + + for (; i < length; i++) { + if (i in this) { + accumulator = fn.call(undefined, accumulator, this[i], i, this); + } + } + + return accumulator; + }; + } + + var JSSourceFilefromCode, optimize, + mapRegExp = /"file":"[^"]+"/; + + //Bind to Closure compiler, but if it is not available, do not sweat it. + try { + JSSourceFilefromCode = java.lang.Class.forName('com.google.javascript.jscomp.JSSourceFile').getMethod('fromCode', [java.lang.String, java.lang.String]); + } catch (e) {} + + //Helper for closure compiler, because of weird Java-JavaScript interactions. + function closurefromCode(filename, content) { + return JSSourceFilefromCode.invoke(null, [filename, content]); + } + + + function getFileWriter(fileName, encoding) { + var outFile = new java.io.File(fileName), outWriter, parentDir; + + parentDir = outFile.getAbsoluteFile().getParentFile(); + if (!parentDir.exists()) { + if (!parentDir.mkdirs()) { + throw "Could not create directory: " + parentDir.getAbsolutePath(); + } + } + + if (encoding) { + outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), encoding); + } else { + outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile)); + } + + return new java.io.BufferedWriter(outWriter); + } + + optimize = { + closure: function (fileName, fileContents, outFileName, keepLines, config) { + config = config || {}; + var result, mappings, optimized, compressed, baseName, writer, + outBaseName, outFileNameMap, outFileNameMapContent, + srcOutFileName, concatNameMap, + jscomp = Packages.com.google.javascript.jscomp, + flags = Packages.com.google.common.flags, + //Set up source input + jsSourceFile = closurefromCode(String(fileName), String(fileContents)), + sourceListArray = new java.util.ArrayList(), + options, option, FLAG_compilation_level, compiler, + Compiler = Packages.com.google.javascript.jscomp.Compiler, + CommandLineRunner = Packages.com.google.javascript.jscomp.CommandLineRunner; + + logger.trace("Minifying file: " + fileName); + + baseName = (new java.io.File(fileName)).getName(); + + //Set up options + options = new jscomp.CompilerOptions(); + for (option in config.CompilerOptions) { + // options are false by default and jslint wanted an if statement in this for loop + if (config.CompilerOptions[option]) { + options[option] = config.CompilerOptions[option]; + } + + } + options.prettyPrint = keepLines || options.prettyPrint; + + FLAG_compilation_level = jscomp.CompilationLevel[config.CompilationLevel || 'SIMPLE_OPTIMIZATIONS']; + FLAG_compilation_level.setOptionsForCompilationLevel(options); + + if (config.generateSourceMaps) { + mappings = new java.util.ArrayList(); + + mappings.add(new com.google.javascript.jscomp.SourceMap.LocationMapping(fileName, baseName + ".src.js")); + options.setSourceMapLocationMappings(mappings); + options.setSourceMapOutputPath(fileName + ".map"); + } + + //Trigger the compiler + Compiler.setLoggingLevel(Packages.java.util.logging.Level[config.loggingLevel || 'WARNING']); + compiler = new Compiler(); + + //fill the sourceArrrayList; we need the ArrayList because the only overload of compile + //accepting the getDefaultExterns return value (a List) also wants the sources as a List + sourceListArray.add(jsSourceFile); + + result = compiler.compile(CommandLineRunner.getDefaultExterns(), sourceListArray, options); + if (result.success) { + optimized = String(compiler.toSource()); + + if (config.generateSourceMaps && result.sourceMap && outFileName) { + outBaseName = (new java.io.File(outFileName)).getName(); + + srcOutFileName = outFileName + ".src.js"; + outFileNameMap = outFileName + ".map"; + + //If previous .map file exists, move it to the ".src.js" + //location. Need to update the sourceMappingURL part in the + //src.js file too. + if (file.exists(outFileNameMap)) { + concatNameMap = outFileNameMap.replace(/\.map$/, '.src.js.map'); + file.saveFile(concatNameMap, file.readFile(outFileNameMap)); + file.saveFile(srcOutFileName, + fileContents.replace(/\/\# sourceMappingURL=(.+).map/, + '/# sourceMappingURL=$1.src.js.map')); + } else { + file.saveUtf8File(srcOutFileName, fileContents); + } + + writer = getFileWriter(outFileNameMap, "utf-8"); + result.sourceMap.appendTo(writer, outFileName); + writer.close(); + + //Not sure how better to do this, but right now the .map file + //leaks the full OS path in the "file" property. Manually + //modify it to not do that. + file.saveFile(outFileNameMap, + file.readFile(outFileNameMap).replace(mapRegExp, '"file":"' + baseName + '"')); + + fileContents = optimized + "\n//# sourceMappingURL=" + outBaseName + ".map"; + } else { + fileContents = optimized; + } + return fileContents; + } else { + throw new Error('Cannot closure compile file: ' + fileName + '. Skipping it.'); + } + + return fileContents; + } + }; + + return optimize; +}); +} + +if(env === 'xpconnect') { +define('xpconnect/optimize', {}); +} +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint plusplus: true, nomen: true, regexp: true */ +/*global define: false */ + +define('optimize', [ 'lang', 'logger', 'env!env/optimize', 'env!env/file', 'parse', + 'pragma', 'uglifyjs/index', 'uglifyjs2', + 'source-map'], +function (lang, logger, envOptimize, file, parse, + pragma, uglify, uglify2, + sourceMap) { + 'use strict'; + + var optimize, + cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/ig, + cssCommentImportRegExp = /\/\*[^\*]*@import[^\*]*\*\//g, + cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g, + SourceMapGenerator = sourceMap.SourceMapGenerator, + SourceMapConsumer =sourceMap.SourceMapConsumer; + + /** + * If an URL from a CSS url value contains start/end quotes, remove them. + * This is not done in the regexp, since my regexp fu is not that strong, + * and the CSS spec allows for ' and " in the URL if they are backslash escaped. + * @param {String} url + */ + function cleanCssUrlQuotes(url) { + //Make sure we are not ending in whitespace. + //Not very confident of the css regexps above that there will not be ending + //whitespace. + url = url.replace(/\s+$/, ""); + + if (url.charAt(0) === "'" || url.charAt(0) === "\"") { + url = url.substring(1, url.length - 1); + } + + return url; + } + + function fixCssUrlPaths(fileName, path, contents, cssPrefix) { + return contents.replace(cssUrlRegExp, function (fullMatch, urlMatch) { + var colonIndex, parts, i, + fixedUrlMatch = cleanCssUrlQuotes(urlMatch); + + fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/"); + + //Only do the work for relative URLs. Skip things that start with / or have + //a protocol. + colonIndex = fixedUrlMatch.indexOf(":"); + if (fixedUrlMatch.charAt(0) !== "/" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { + //It is a relative URL, tack on the cssPrefix and path prefix + urlMatch = cssPrefix + path + fixedUrlMatch; + + } else { + logger.trace(fileName + "\n URL not a relative URL, skipping: " + urlMatch); + } + + //Collapse .. and . + parts = urlMatch.split("/"); + for (i = parts.length - 1; i > 0; i--) { + if (parts[i] === ".") { + parts.splice(i, 1); + } else if (parts[i] === "..") { + if (i !== 0 && parts[i - 1] !== "..") { + parts.splice(i - 1, 2); + i -= 1; + } + } + } + + return "url(" + parts.join("/") + ")"; + }); + } + + /** + * Inlines nested stylesheets that have @import calls in them. + * @param {String} fileName the file name + * @param {String} fileContents the file contents + * @param {String} cssImportIgnore comma delimited string of files to ignore + * @param {String} cssPrefix string to be prefixed before relative URLs + * @param {Object} included an object used to track the files already imported + */ + function flattenCss(fileName, fileContents, cssImportIgnore, cssPrefix, included, topLevel) { + //Find the last slash in the name. + fileName = fileName.replace(lang.backSlashRegExp, "/"); + var endIndex = fileName.lastIndexOf("/"), + //Make a file path based on the last slash. + //If no slash, so must be just a file name. Use empty string then. + filePath = (endIndex !== -1) ? fileName.substring(0, endIndex + 1) : "", + //store a list of merged files + importList = [], + skippedList = []; + + //First make a pass by removing any commented out @import calls. + fileContents = fileContents.replace(cssCommentImportRegExp, ''); + + //Make sure we have a delimited ignore list to make matching faster + if (cssImportIgnore && cssImportIgnore.charAt(cssImportIgnore.length - 1) !== ",") { + cssImportIgnore += ","; + } + + fileContents = fileContents.replace(cssImportRegExp, function (fullMatch, urlStart, importFileName, urlEnd, mediaTypes) { + //Only process media type "all" or empty media type rules. + if (mediaTypes && ((mediaTypes.replace(/^\s\s*/, '').replace(/\s\s*$/, '')) !== "all")) { + skippedList.push(fileName); + return fullMatch; + } + + importFileName = cleanCssUrlQuotes(importFileName); + + //Ignore the file import if it is part of an ignore list. + if (cssImportIgnore && cssImportIgnore.indexOf(importFileName + ",") !== -1) { + return fullMatch; + } + + //Make sure we have a unix path for the rest of the operation. + importFileName = importFileName.replace(lang.backSlashRegExp, "/"); + + try { + //if a relative path, then tack on the filePath. + //If it is not a relative path, then the readFile below will fail, + //and we will just skip that import. + var fullImportFileName = importFileName.charAt(0) === "/" ? importFileName : filePath + importFileName, + importContents = file.readFile(fullImportFileName), + importEndIndex, importPath, flat; + + //Skip the file if it has already been included. + if (included[fullImportFileName]) { + return ''; + } + included[fullImportFileName] = true; + + //Make sure to flatten any nested imports. + flat = flattenCss(fullImportFileName, importContents, cssImportIgnore, cssPrefix, included); + importContents = flat.fileContents; + + if (flat.importList.length) { + importList.push.apply(importList, flat.importList); + } + if (flat.skippedList.length) { + skippedList.push.apply(skippedList, flat.skippedList); + } + + //Make the full import path + importEndIndex = importFileName.lastIndexOf("/"); + + //Make a file path based on the last slash. + //If no slash, so must be just a file name. Use empty string then. + importPath = (importEndIndex !== -1) ? importFileName.substring(0, importEndIndex + 1) : ""; + + //fix url() on relative import (#5) + importPath = importPath.replace(/^\.\//, ''); + + //Modify URL paths to match the path represented by this file. + importContents = fixCssUrlPaths(importFileName, importPath, importContents, cssPrefix); + + importList.push(fullImportFileName); + return importContents; + } catch (e) { + logger.warn(fileName + "\n Cannot inline css import, skipping: " + importFileName); + return fullMatch; + } + }); + + if (cssPrefix && topLevel) { + //Modify URL paths to match the path represented by this file. + fileContents = fixCssUrlPaths(fileName, '', fileContents, cssPrefix); + } + + return { + importList : importList, + skippedList: skippedList, + fileContents : fileContents + }; + } + + optimize = { + /** + * Optimizes a file that contains JavaScript content. Optionally collects + * plugin resources mentioned in a file, and then passes the content + * through an minifier if one is specified via config.optimize. + * + * @param {String} fileName the name of the file to optimize + * @param {String} fileContents the contents to optimize. If this is + * a null value, then fileName will be used to read the fileContents. + * @param {String} outFileName the name of the file to use for the + * saved optimized content. + * @param {Object} config the build config object. + * @param {Array} [pluginCollector] storage for any plugin resources + * found. + */ + jsFile: function (fileName, fileContents, outFileName, config, pluginCollector) { + if (!fileContents) { + fileContents = file.readFile(fileName); + } + + fileContents = optimize.js(fileName, fileContents, outFileName, config, pluginCollector); + + file.saveUtf8File(outFileName, fileContents); + }, + + /** + * Optimizes a file that contains JavaScript content. Optionally collects + * plugin resources mentioned in a file, and then passes the content + * through an minifier if one is specified via config.optimize. + * + * @param {String} fileName the name of the file that matches the + * fileContents. + * @param {String} fileContents the string of JS to optimize. + * @param {Object} [config] the build config object. + * @param {Array} [pluginCollector] storage for any plugin resources + * found. + */ + js: function (fileName, fileContents, outFileName, config, pluginCollector) { + var optFunc, optConfig, + parts = (String(config.optimize)).split('.'), + optimizerName = parts[0], + keepLines = parts[1] === 'keepLines', + licenseContents = ''; + + config = config || {}; + + //Apply pragmas/namespace renaming + fileContents = pragma.process(fileName, fileContents, config, 'OnSave', pluginCollector); + + //Optimize the JS files if asked. + if (optimizerName && optimizerName !== 'none') { + optFunc = envOptimize[optimizerName] || optimize.optimizers[optimizerName]; + if (!optFunc) { + throw new Error('optimizer with name of "' + + optimizerName + + '" not found for this environment'); + } + + optConfig = config[optimizerName] || {}; + if (config.generateSourceMaps) { + optConfig.generateSourceMaps = !!config.generateSourceMaps; + } + + try { + if (config.preserveLicenseComments) { + //Pull out any license comments for prepending after optimization. + try { + licenseContents = parse.getLicenseComments(fileName, fileContents); + } catch (e) { + throw new Error('Cannot parse file: ' + fileName + ' for comments. Skipping it. Error is:\n' + e.toString()); + } + } + + fileContents = licenseContents + optFunc(fileName, + fileContents, + outFileName, + keepLines, + optConfig); + } catch (e) { + if (config.throwWhen && config.throwWhen.optimize) { + throw e; + } else { + logger.error(e); + } + } + } + + return fileContents; + }, + + /** + * Optimizes one CSS file, inlining @import calls, stripping comments, and + * optionally removes line returns. + * @param {String} fileName the path to the CSS file to optimize + * @param {String} outFileName the path to save the optimized file. + * @param {Object} config the config object with the optimizeCss and + * cssImportIgnore options. + */ + cssFile: function (fileName, outFileName, config) { + + //Read in the file. Make sure we have a JS string. + var originalFileContents = file.readFile(fileName), + flat = flattenCss(fileName, originalFileContents, config.cssImportIgnore, config.cssPrefix, {}, true), + //Do not use the flattened CSS if there was one that was skipped. + fileContents = flat.skippedList.length ? originalFileContents : flat.fileContents, + startIndex, endIndex, buildText, comment; + + if (flat.skippedList.length) { + logger.warn('Cannot inline @imports for ' + fileName + + ',\nthe following files had media queries in them:\n' + + flat.skippedList.join('\n')); + } + + //Do comment removal. + try { + if (config.optimizeCss.indexOf(".keepComments") === -1) { + startIndex = 0; + //Get rid of comments. + while ((startIndex = fileContents.indexOf("/*", startIndex)) !== -1) { + endIndex = fileContents.indexOf("*/", startIndex + 2); + if (endIndex === -1) { + throw "Improper comment in CSS file: " + fileName; + } + comment = fileContents.substring(startIndex, endIndex); + + if (config.preserveLicenseComments && + (comment.indexOf('license') !== -1 || + comment.indexOf('opyright') !== -1 || + comment.indexOf('(c)') !== -1)) { + //Keep the comment, just increment the startIndex + startIndex = endIndex; + } else { + fileContents = fileContents.substring(0, startIndex) + fileContents.substring(endIndex + 2, fileContents.length); + startIndex = 0; + } + } + } + //Get rid of newlines. + if (config.optimizeCss.indexOf(".keepLines") === -1) { + fileContents = fileContents.replace(/[\r\n]/g, " "); + fileContents = fileContents.replace(/\s+/g, " "); + fileContents = fileContents.replace(/\{\s/g, "{"); + fileContents = fileContents.replace(/\s\}/g, "}"); + } else { + //Remove multiple empty lines. + fileContents = fileContents.replace(/(\r\n)+/g, "\r\n"); + fileContents = fileContents.replace(/(\n)+/g, "\n"); + } + } catch (e) { + fileContents = originalFileContents; + logger.error("Could not optimized CSS file: " + fileName + ", error: " + e); + } + + file.saveUtf8File(outFileName, fileContents); + + //text output to stdout and/or written to build.txt file + buildText = "\n"+ outFileName.replace(config.dir, "") +"\n----------------\n"; + flat.importList.push(fileName); + buildText += flat.importList.map(function(path){ + return path.replace(config.dir, ""); + }).join("\n"); + + return { + importList: flat.importList, + buildText: buildText +"\n" + }; + }, + + /** + * Optimizes CSS files, inlining @import calls, stripping comments, and + * optionally removes line returns. + * @param {String} startDir the path to the top level directory + * @param {Object} config the config object with the optimizeCss and + * cssImportIgnore options. + */ + css: function (startDir, config) { + var buildText = "", + importList = [], + shouldRemove = config.dir && config.removeCombined, + i, fileName, result, fileList; + if (config.optimizeCss.indexOf("standard") !== -1) { + fileList = file.getFilteredFileList(startDir, /\.css$/, true); + if (fileList) { + for (i = 0; i < fileList.length; i++) { + fileName = fileList[i]; + logger.trace("Optimizing (" + config.optimizeCss + ") CSS file: " + fileName); + result = optimize.cssFile(fileName, fileName, config); + buildText += result.buildText; + if (shouldRemove) { + result.importList.pop(); + importList = importList.concat(result.importList); + } + } + } + + if (shouldRemove) { + importList.forEach(function (path) { + if (file.exists(path)) { + file.deleteFile(path); + } + }); + } + } + return buildText; + }, + + optimizers: { + uglify: function (fileName, fileContents, outFileName, keepLines, config) { + var parser = uglify.parser, + processor = uglify.uglify, + ast, errMessage, errMatch; + + config = config || {}; + + logger.trace("Uglifying file: " + fileName); + + try { + ast = parser.parse(fileContents, config.strict_semicolons); + if (config.no_mangle !== true) { + ast = processor.ast_mangle(ast, config); + } + ast = processor.ast_squeeze(ast, config); + + fileContents = processor.gen_code(ast, config); + + if (config.max_line_length) { + fileContents = processor.split_lines(fileContents, config.max_line_length); + } + + //Add trailing semicolon to match uglifyjs command line version + fileContents += ';'; + } catch (e) { + errMessage = e.toString(); + errMatch = /\nError(\r)?\n/.exec(errMessage); + if (errMatch) { + errMessage = errMessage.substring(0, errMatch.index); + } + throw new Error('Cannot uglify file: ' + fileName + '. Skipping it. Error is:\n' + errMessage); + } + return fileContents; + }, + uglify2: function (fileName, fileContents, outFileName, keepLines, config) { + var result, existingMap, resultMap, finalMap, sourceIndex, + uconfig = {}, + existingMapPath = outFileName + '.map', + baseName = fileName && fileName.split('/').pop(); + + config = config || {}; + + lang.mixin(uconfig, config, true); + + uconfig.fromString = true; + + if (config.generateSourceMaps && outFileName) { + uconfig.outSourceMap = baseName; + + if (file.exists(existingMapPath)) { + uconfig.inSourceMap = existingMapPath; + existingMap = JSON.parse(file.readFile(existingMapPath)); + } + } + + logger.trace("Uglify2 file: " + fileName); + + try { + //var tempContents = fileContents.replace(/\/\/\# sourceMappingURL=.*$/, ''); + result = uglify2.minify(fileContents, uconfig, baseName + '.src.js'); + if (uconfig.outSourceMap && result.map) { + resultMap = result.map; + if (existingMap) { + resultMap = JSON.parse(resultMap); + finalMap = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(resultMap)); + finalMap.applySourceMap(new SourceMapConsumer(existingMap)); + resultMap = finalMap.toString(); + } else { + file.saveFile(outFileName + '.src.js', fileContents); + } + file.saveFile(outFileName + '.map', resultMap); + fileContents = result.code + "\n//# sourceMappingURL=" + baseName + ".map"; + } else { + fileContents = result.code; + } + } catch (e) { + throw new Error('Cannot uglify2 file: ' + fileName + '. Skipping it. Error is:\n' + e.toString()); + } + return fileContents; + } + } + }; + + return optimize; +}); +/** + * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +/* + * This file patches require.js to communicate with the build system. + */ + +//Using sloppy since this uses eval for some code like plugins, +//which may not be strict mode compliant. So if use strict is used +//below they will have strict rules applied and may cause an error. +/*jslint sloppy: true, nomen: true, plusplus: true, regexp: true */ +/*global require, define: true */ + +//NOT asking for require as a dependency since the goal is to modify the +//global require below +define('requirePatch', [ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'commonJs', 'prim'], function ( + file, + pragma, + parse, + lang, + logger, + commonJs, + prim +) { + + var allowRun = true, + hasProp = lang.hasProp, + falseProp = lang.falseProp, + getOwn = lang.getOwn; + + //This method should be called when the patches to require should take hold. + return function () { + if (!allowRun) { + return; + } + allowRun = false; + + var layer, + pluginBuilderRegExp = /(["']?)pluginBuilder(["']?)\s*[=\:]\s*["']([^'"\s]+)["']/, + oldNewContext = require.s.newContext, + oldDef, + + //create local undefined values for module and exports, + //so that when files are evaled in this function they do not + //see the node values used for r.js + exports, + module; + + /** + * Reset "global" build caches that are kept around between + * build layer builds. Useful to do when there are multiple + * top level requirejs.optimize() calls. + */ + require._cacheReset = function () { + //Stored raw text caches, used by browser use. + require._cachedRawText = {}; + //Stored cached file contents for reuse in other layers. + require._cachedFileContents = {}; + //Store which cached files contain a require definition. + require._cachedDefinesRequireUrls = {}; + }; + require._cacheReset(); + + /** + * Makes sure the URL is something that can be supported by the + * optimization tool. + * @param {String} url + * @returns {Boolean} + */ + require._isSupportedBuildUrl = function (url) { + //Ignore URLs with protocols, hosts or question marks, means either network + //access is needed to fetch it or it is too dynamic. Note that + //on Windows, full paths are used for some urls, which include + //the drive, like c:/something, so need to test for something other + //than just a colon. + if (url.indexOf("://") === -1 && url.indexOf("?") === -1 && + url.indexOf('empty:') !== 0 && url.indexOf('//') !== 0) { + return true; + } else { + if (!layer.ignoredUrls[url]) { + if (url.indexOf('empty:') === -1) { + logger.info('Cannot optimize network URL, skipping: ' + url); + } + layer.ignoredUrls[url] = true; + } + return false; + } + }; + + function normalizeUrlWithBase(context, moduleName, url) { + //Adjust the URL if it was not transformed to use baseUrl. + if (require.jsExtRegExp.test(moduleName)) { + url = (context.config.dir || context.config.dirBaseUrl) + url; + } + return url; + } + + //Overrides the new context call to add existing tracking features. + require.s.newContext = function (name) { + var context = oldNewContext(name), + oldEnable = context.enable, + moduleProto = context.Module.prototype, + oldInit = moduleProto.init, + oldCallPlugin = moduleProto.callPlugin; + + //Only do this for the context used for building. + if (name === '_') { + //For build contexts, do everything sync + context.nextTick = function (fn) { + fn(); + }; + + context.needFullExec = {}; + context.fullExec = {}; + context.plugins = {}; + context.buildShimExports = {}; + + //Override the shim exports function generator to just + //spit out strings that can be used in the stringified + //build output. + context.makeShimExports = function (value) { + function fn() { + return '(function (global) {\n' + + ' return function () {\n' + + ' var ret, fn;\n' + + (value.init ? + (' fn = ' + value.init.toString() + ';\n' + + ' ret = fn.apply(global, arguments);\n') : '') + + (value.exports ? + ' return ret || global.' + value.exports + ';\n' : + ' return ret;\n') + + ' };\n' + + '}(this))'; + } + + return fn; + }; + + context.enable = function (depMap, parent) { + var id = depMap.id, + parentId = parent && parent.map.id, + needFullExec = context.needFullExec, + fullExec = context.fullExec, + mod = getOwn(context.registry, id); + + if (mod && !mod.defined) { + if (parentId && getOwn(needFullExec, parentId)) { + needFullExec[id] = true; + } + + } else if ((getOwn(needFullExec, id) && falseProp(fullExec, id)) || + (parentId && getOwn(needFullExec, parentId) && + falseProp(fullExec, id))) { + context.require.undef(id); + } + + return oldEnable.apply(context, arguments); + }; + + //Override load so that the file paths can be collected. + context.load = function (moduleName, url) { + /*jslint evil: true */ + var contents, pluginBuilderMatch, builderName, + shim, shimExports; + + //Do not mark the url as fetched if it is + //not an empty: URL, used by the optimizer. + //In that case we need to be sure to call + //load() for each module that is mapped to + //empty: so that dependencies are satisfied + //correctly. + if (url.indexOf('empty:') === 0) { + delete context.urlFetched[url]; + } + + //Only handle urls that can be inlined, so that means avoiding some + //URLs like ones that require network access or may be too dynamic, + //like JSONP + if (require._isSupportedBuildUrl(url)) { + //Adjust the URL if it was not transformed to use baseUrl. + url = normalizeUrlWithBase(context, moduleName, url); + + //Save the module name to path and path to module name mappings. + layer.buildPathMap[moduleName] = url; + layer.buildFileToModule[url] = moduleName; + + if (hasProp(context.plugins, moduleName)) { + //plugins need to have their source evaled as-is. + context.needFullExec[moduleName] = true; + } + + prim().start(function () { + if (hasProp(require._cachedFileContents, url) && + (falseProp(context.needFullExec, moduleName) || + getOwn(context.fullExec, moduleName))) { + contents = require._cachedFileContents[url]; + + //If it defines require, mark it so it can be hoisted. + //Done here and in the else below, before the + //else block removes code from the contents. + //Related to #263 + if (!layer.existingRequireUrl && require._cachedDefinesRequireUrls[url]) { + layer.existingRequireUrl = url; + } + } else { + //Load the file contents, process for conditionals, then + //evaluate it. + return require._cacheReadAsync(url).then(function (text) { + contents = text; + + if (context.config.cjsTranslate && + (!context.config.shim || !lang.hasProp(context.config.shim, moduleName))) { + contents = commonJs.convert(url, contents); + } + + //If there is a read filter, run it now. + if (context.config.onBuildRead) { + contents = context.config.onBuildRead(moduleName, url, contents); + } + + contents = pragma.process(url, contents, context.config, 'OnExecute'); + + //Find out if the file contains a require() definition. Need to know + //this so we can inject plugins right after it, but before they are needed, + //and to make sure this file is first, so that define calls work. + try { + if (!layer.existingRequireUrl && parse.definesRequire(url, contents)) { + layer.existingRequireUrl = url; + require._cachedDefinesRequireUrls[url] = true; + } + } catch (e1) { + throw new Error('Parse error using esprima ' + + 'for file: ' + url + '\n' + e1); + } + }).then(function () { + if (hasProp(context.plugins, moduleName)) { + //This is a loader plugin, check to see if it has a build extension, + //otherwise the plugin will act as the plugin builder too. + pluginBuilderMatch = pluginBuilderRegExp.exec(contents); + if (pluginBuilderMatch) { + //Load the plugin builder for the plugin contents. + builderName = context.makeModuleMap(pluginBuilderMatch[3], + context.makeModuleMap(moduleName), + null, + true).id; + return require._cacheReadAsync(context.nameToUrl(builderName)); + } + } + return contents; + }).then(function (text) { + contents = text; + + //Parse out the require and define calls. + //Do this even for plugins in case they have their own + //dependencies that may be separate to how the pluginBuilder works. + try { + if (falseProp(context.needFullExec, moduleName)) { + contents = parse(moduleName, url, contents, { + insertNeedsDefine: true, + has: context.config.has, + findNestedDependencies: context.config.findNestedDependencies + }); + } + } catch (e2) { + throw new Error('Parse error using esprima ' + + 'for file: ' + url + '\n' + e2); + } + + require._cachedFileContents[url] = contents; + }); + } + }).then(function () { + if (contents) { + eval(contents); + } + + try { + //If have a string shim config, and this is + //a fully executed module, try to see if + //it created a variable in this eval scope + if (getOwn(context.needFullExec, moduleName)) { + shim = getOwn(context.config.shim, moduleName); + if (shim && shim.exports) { + shimExports = eval(shim.exports); + if (typeof shimExports !== 'undefined') { + context.buildShimExports[moduleName] = shimExports; + } + } + } + + //Need to close out completion of this module + //so that listeners will get notified that it is available. + context.completeLoad(moduleName); + } catch (e) { + //Track which module could not complete loading. + if (!e.moduleTree) { + e.moduleTree = []; + } + e.moduleTree.push(moduleName); + throw e; + } + }).then(null, function (eOuter) { + + if (!eOuter.fileName) { + eOuter.fileName = url; + } + throw eOuter; + }).end(); + } else { + //With unsupported URLs still need to call completeLoad to + //finish loading. + context.completeLoad(moduleName); + } + }; + + //Marks module has having a name, and optionally executes the + //callback, but only if it meets certain criteria. + context.execCb = function (name, cb, args, exports) { + var buildShimExports = getOwn(layer.context.buildShimExports, name); + + if (buildShimExports) { + return buildShimExports; + } else if (cb.__requireJsBuild || getOwn(layer.context.needFullExec, name)) { + return cb.apply(exports, args); + } + return undefined; + }; + + moduleProto.init = function (depMaps) { + if (context.needFullExec[this.map.id]) { + lang.each(depMaps, lang.bind(this, function (depMap) { + if (typeof depMap === 'string') { + depMap = context.makeModuleMap(depMap, + (this.map.isDefine ? this.map : this.map.parentMap)); + } + + if (!context.fullExec[depMap.id]) { + context.require.undef(depMap.id); + } + })); + } + + return oldInit.apply(this, arguments); + }; + + moduleProto.callPlugin = function () { + var map = this.map, + pluginMap = context.makeModuleMap(map.prefix), + pluginId = pluginMap.id, + pluginMod = getOwn(context.registry, pluginId); + + context.plugins[pluginId] = true; + context.needFullExec[pluginId] = true; + + //If the module is not waiting to finish being defined, + //undef it and start over, to get full execution. + if (falseProp(context.fullExec, pluginId) && (!pluginMod || pluginMod.defined)) { + context.require.undef(pluginMap.id); + } + + return oldCallPlugin.apply(this, arguments); + }; + } + + return context; + }; + + //Clear up the existing context so that the newContext modifications + //above will be active. + delete require.s.contexts._; + + /** Reset state for each build layer pass. */ + require._buildReset = function () { + var oldContext = require.s.contexts._; + + //Clear up the existing context. + delete require.s.contexts._; + + //Set up new context, so the layer object can hold onto it. + require({}); + + layer = require._layer = { + buildPathMap: {}, + buildFileToModule: {}, + buildFilePaths: [], + pathAdded: {}, + modulesWithNames: {}, + needsDefine: {}, + existingRequireUrl: "", + ignoredUrls: {}, + context: require.s.contexts._ + }; + + //Return the previous context in case it is needed, like for + //the basic config object. + return oldContext; + }; + + require._buildReset(); + + //Override define() to catch modules that just define an object, so that + //a dummy define call is not put in the build file for them. They do + //not end up getting defined via context.execCb, so we need to catch them + //at the define call. + oldDef = define; + + //This function signature does not have to be exact, just match what we + //are looking for. + define = function (name) { + if (typeof name === "string" && falseProp(layer.needsDefine, name)) { + layer.modulesWithNames[name] = true; + } + return oldDef.apply(require, arguments); + }; + + define.amd = oldDef.amd; + + //Add some utilities for plugins + require._readFile = file.readFile; + require._fileExists = function (path) { + return file.exists(path); + }; + + //Called when execManager runs for a dependency. Used to figure out + //what order of execution. + require.onResourceLoad = function (context, map) { + var id = map.id, + url; + + //If build needed a full execution, indicate it + //has been done now. But only do it if the context is tracking + //that. Only valid for the context used in a build, not for + //other contexts being run, like for useLib, plain requirejs + //use in node/rhino. + if (context.needFullExec && getOwn(context.needFullExec, id)) { + context.fullExec[id] = true; + } + + //A plugin. + if (map.prefix) { + if (falseProp(layer.pathAdded, id)) { + layer.buildFilePaths.push(id); + //For plugins the real path is not knowable, use the name + //for both module to file and file to module mappings. + layer.buildPathMap[id] = id; + layer.buildFileToModule[id] = id; + layer.modulesWithNames[id] = true; + layer.pathAdded[id] = true; + } + } else if (map.url && require._isSupportedBuildUrl(map.url)) { + //If the url has not been added to the layer yet, and it + //is from an actual file that was loaded, add it now. + url = normalizeUrlWithBase(context, id, map.url); + if (!layer.pathAdded[url] && getOwn(layer.buildPathMap, id)) { + //Remember the list of dependencies for this layer. + layer.buildFilePaths.push(url); + layer.pathAdded[url] = true; + } + } + }; + + //Called by output of the parse() function, when a file does not + //explicitly call define, probably just require, but the parse() + //function normalizes on define() for dependency mapping and file + //ordering works correctly. + require.needsDefine = function (moduleName) { + layer.needsDefine[moduleName] = true; + }; + }; +}); +/** + * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint */ +/*global define: false, console: false */ + +define('commonJs', ['env!env/file', 'parse'], function (file, parse) { + 'use strict'; + var commonJs = { + //Set to false if you do not want this file to log. Useful in environments + //like node where you want the work to happen without noise. + useLog: true, + + convertDir: function (commonJsPath, savePath) { + var fileList, i, + jsFileRegExp = /\.js$/, + fileName, convertedFileName, fileContents; + + //Get list of files to convert. + fileList = file.getFilteredFileList(commonJsPath, /\w/, true); + + //Normalize on front slashes and make sure the paths do not end in a slash. + commonJsPath = commonJsPath.replace(/\\/g, "/"); + savePath = savePath.replace(/\\/g, "/"); + if (commonJsPath.charAt(commonJsPath.length - 1) === "/") { + commonJsPath = commonJsPath.substring(0, commonJsPath.length - 1); + } + if (savePath.charAt(savePath.length - 1) === "/") { + savePath = savePath.substring(0, savePath.length - 1); + } + + //Cycle through all the JS files and convert them. + if (!fileList || !fileList.length) { + if (commonJs.useLog) { + if (commonJsPath === "convert") { + //A request just to convert one file. + console.log('\n\n' + commonJs.convert(savePath, file.readFile(savePath))); + } else { + console.log("No files to convert in directory: " + commonJsPath); + } + } + } else { + for (i = 0; i < fileList.length; i++) { + fileName = fileList[i]; + convertedFileName = fileName.replace(commonJsPath, savePath); + + //Handle JS files. + if (jsFileRegExp.test(fileName)) { + fileContents = file.readFile(fileName); + fileContents = commonJs.convert(fileName, fileContents); + file.saveUtf8File(convertedFileName, fileContents); + } else { + //Just copy the file over. + file.copyFile(fileName, convertedFileName, true); + } + } + } + }, + + /** + * Does the actual file conversion. + * + * @param {String} fileName the name of the file. + * + * @param {String} fileContents the contents of a file :) + * + * @returns {String} the converted contents + */ + convert: function (fileName, fileContents) { + //Strip out comments. + try { + var preamble = '', + commonJsProps = parse.usesCommonJs(fileName, fileContents); + + //First see if the module is not already RequireJS-formatted. + if (parse.usesAmdOrRequireJs(fileName, fileContents) || !commonJsProps) { + return fileContents; + } + + if (commonJsProps.dirname || commonJsProps.filename) { + preamble = 'var __filename = module.uri || "", ' + + '__dirname = __filename.substring(0, __filename.lastIndexOf("/") + 1); '; + } + + //Construct the wrapper boilerplate. + fileContents = 'define(function (require, exports, module) {' + + preamble + + fileContents + + '\n});\n'; + + } catch (e) { + console.log("commonJs.convert: COULD NOT CONVERT: " + fileName + ", so skipping it. Error was: " + e); + return fileContents; + } + + return fileContents; + } + }; + + return commonJs; +}); +/** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/*jslint plusplus: true, nomen: true, regexp: true */ +/*global define, requirejs */ + + +define('build', function (require) { + 'use strict'; + + var build, buildBaseConfig, + lang = require('lang'), + prim = require('prim'), + logger = require('logger'), + file = require('env!env/file'), + parse = require('parse'), + optimize = require('optimize'), + pragma = require('pragma'), + transform = require('transform'), + requirePatch = require('requirePatch'), + env = require('env'), + commonJs = require('commonJs'), + SourceMapGenerator = require('source-map/source-map-generator'), + hasProp = lang.hasProp, + getOwn = lang.getOwn, + falseProp = lang.falseProp, + endsWithSemiColonRegExp = /;\s*$/, + resourceIsModuleIdRegExp = /^[\w\/\\\.]+$/; + + prim.nextTick = function (fn) { + fn(); + }; + + //Now map require to the outermost requirejs, now that we have + //local dependencies for this module. The rest of the require use is + //manipulating the requirejs loader. + require = requirejs; + + //Caching function for performance. Attached to + //require so it can be reused in requirePatch.js. _cachedRawText + //set up by requirePatch.js + require._cacheReadAsync = function (path, encoding) { + var d; + + if (lang.hasProp(require._cachedRawText, path)) { + d = prim(); + d.resolve(require._cachedRawText[path]); + return d.promise; + } else { + return file.readFileAsync(path, encoding).then(function (text) { + require._cachedRawText[path] = text; + return text; + }); + } + }; + + buildBaseConfig = { + appDir: "", + pragmas: {}, + paths: {}, + optimize: "uglify", + optimizeCss: "standard.keepLines", + inlineText: true, + isBuild: true, + optimizeAllPluginResources: false, + findNestedDependencies: false, + preserveLicenseComments: true, + //By default, all files/directories are copied, unless + //they match this regexp, by default just excludes .folders + dirExclusionRegExp: file.dirExclusionRegExp, + _buildPathToModuleIndex: {} + }; + + /** + * Some JS may not be valid if concatenated with other JS, in particular + * the style of omitting semicolons and rely on ASI. Add a semicolon in + * those cases. + */ + function addSemiColon(text, config) { + if (config.skipSemiColonInsertion || endsWithSemiColonRegExp.test(text)) { + return text; + } else { + return text + ";"; + } + } + + function endsWithSlash(dirName) { + if (dirName.charAt(dirName.length - 1) !== "/") { + dirName += "/"; + } + return dirName; + } + + //Method used by plugin writeFile calls, defined up here to avoid + //jslint warning about "making a function in a loop". + function makeWriteFile(namespace, layer) { + function writeFile(name, contents) { + logger.trace('Saving plugin-optimized file: ' + name); + file.saveUtf8File(name, contents); + } + + writeFile.asModule = function (moduleName, fileName, contents) { + writeFile(fileName, + build.toTransport(namespace, moduleName, fileName, contents, layer)); + }; + + return writeFile; + } + + /** + * Main API entry point into the build. The args argument can either be + * an array of arguments (like the onese passed on a command-line), + * or it can be a JavaScript object that has the format of a build profile + * file. + * + * If it is an object, then in addition to the normal properties allowed in + * a build profile file, the object should contain one other property: + * + * The object could also contain a "buildFile" property, which is a string + * that is the file path to a build profile that contains the rest + * of the build profile directives. + * + * This function does not return a status, it should throw an error if + * there is a problem completing the build. + */ + build = function (args) { + var buildFile, cmdConfig, errorMsg, errorStack, stackMatch, errorTree, + i, j, errorMod, + stackRegExp = /( {4}at[^\n]+)\n/, + standardIndent = ' '; + + return prim().start(function () { + if (!args || lang.isArray(args)) { + if (!args || args.length < 1) { + logger.error("build.js buildProfile.js\n" + + "where buildProfile.js is the name of the build file (see example.build.js for hints on how to make a build file)."); + return undefined; + } + + //Next args can include a build file path as well as other build args. + //build file path comes first. If it does not contain an = then it is + //a build file path. Otherwise, just all build args. + if (args[0].indexOf("=") === -1) { + buildFile = args[0]; + args.splice(0, 1); + } + + //Remaining args are options to the build + cmdConfig = build.convertArrayToObject(args); + cmdConfig.buildFile = buildFile; + } else { + cmdConfig = args; + } + + return build._run(cmdConfig); + }).then(null, function (e) { + var err; + + errorMsg = e.toString(); + errorTree = e.moduleTree; + stackMatch = stackRegExp.exec(errorMsg); + + if (stackMatch) { + errorMsg += errorMsg.substring(0, stackMatch.index + stackMatch[0].length + 1); + } + + //If a module tree that shows what module triggered the error, + //print it out. + if (errorTree && errorTree.length > 0) { + errorMsg += '\nIn module tree:\n'; + + for (i = errorTree.length - 1; i > -1; i--) { + errorMod = errorTree[i]; + if (errorMod) { + for (j = errorTree.length - i; j > -1; j--) { + errorMsg += standardIndent; + } + errorMsg += errorMod + '\n'; + } + } + + logger.error(errorMsg); + } + + errorStack = e.stack; + + if (typeof args === 'string' && args.indexOf('stacktrace=true') !== -1) { + errorMsg += '\n' + errorStack; + } else { + if (!stackMatch && errorStack) { + //Just trim out the first "at" in the stack. + stackMatch = stackRegExp.exec(errorStack); + if (stackMatch) { + errorMsg += '\n' + stackMatch[0] || ''; + } + } + } + + err = new Error(errorMsg); + err.originalError = e; + throw err; + }); + }; + + build._run = function (cmdConfig) { + var buildPaths, fileName, fileNames, + paths, i, + baseConfig, config, + modules, srcPath, buildContext, + destPath, moduleMap, parentModuleMap, context, + resources, resource, plugin, fileContents, + pluginProcessed = {}, + buildFileContents = "", + pluginCollector = {}; + + return prim().start(function () { + var prop; + + //Can now run the patches to require.js to allow it to be used for + //build generation. Do it here instead of at the top of the module + //because we want normal require behavior to load the build tool + //then want to switch to build mode. + requirePatch(); + + config = build.createConfig(cmdConfig); + paths = config.paths; + + //Remove the previous build dir, in case it contains source transforms, + //like the ones done with onBuildRead and onBuildWrite. + if (config.dir && !config.keepBuildDir && file.exists(config.dir)) { + file.deleteFile(config.dir); + } + + if (!config.out && !config.cssIn) { + //This is not just a one-off file build but a full build profile, with + //lots of files to process. + + //First copy all the baseUrl content + file.copyDir((config.appDir || config.baseUrl), config.dir, /\w/, true); + + //Adjust baseUrl if config.appDir is in play, and set up build output paths. + buildPaths = {}; + if (config.appDir) { + //All the paths should be inside the appDir, so just adjust + //the paths to use the dirBaseUrl + for (prop in paths) { + if (hasProp(paths, prop)) { + buildPaths[prop] = paths[prop].replace(config.appDir, config.dir); + } + } + } else { + //If no appDir, then make sure to copy the other paths to this directory. + for (prop in paths) { + if (hasProp(paths, prop)) { + //Set up build path for each path prefix, but only do so + //if the path falls out of the current baseUrl + if (paths[prop].indexOf(config.baseUrl) === 0) { + buildPaths[prop] = paths[prop].replace(config.baseUrl, config.dirBaseUrl); + } else { + buildPaths[prop] = paths[prop] === 'empty:' ? 'empty:' : prop.replace(/\./g, "/"); + + //Make sure source path is fully formed with baseUrl, + //if it is a relative URL. + srcPath = paths[prop]; + if (srcPath.indexOf('/') !== 0 && srcPath.indexOf(':') === -1) { + srcPath = config.baseUrl + srcPath; + } + + destPath = config.dirBaseUrl + buildPaths[prop]; + + //Skip empty: paths + if (srcPath !== 'empty:') { + //If the srcPath is a directory, copy the whole directory. + if (file.exists(srcPath) && file.isDirectory(srcPath)) { + //Copy files to build area. Copy all files (the /\w/ regexp) + file.copyDir(srcPath, destPath, /\w/, true); + } else { + //Try a .js extension + srcPath += '.js'; + destPath += '.js'; + file.copyFile(srcPath, destPath); + } + } + } + } + } + } + } + + //Figure out source file location for each module layer. Do this by seeding require + //with source area configuration. This is needed so that later the module layers + //can be manually copied over to the source area, since the build may be + //require multiple times and the above copyDir call only copies newer files. + require({ + baseUrl: config.baseUrl, + paths: paths, + packagePaths: config.packagePaths, + packages: config.packages + }); + buildContext = require.s.contexts._; + modules = config.modules; + + if (modules) { + modules.forEach(function (module) { + if (module.name) { + module._sourcePath = buildContext.nameToUrl(module.name); + //If the module does not exist, and this is not a "new" module layer, + //as indicated by a true "create" property on the module, and + //it is not a plugin-loaded resource, and there is no + //'rawText' containing the module's source then throw an error. + if (!file.exists(module._sourcePath) && !module.create && + module.name.indexOf('!') === -1 && + (!config.rawText || !lang.hasProp(config.rawText, module.name))) { + throw new Error("ERROR: module path does not exist: " + + module._sourcePath + " for module named: " + module.name + + ". Path is relative to: " + file.absPath('.')); + } + } + }); + } + + if (config.out) { + //Just set up the _buildPath for the module layer. + require(config); + if (!config.cssIn) { + config.modules[0]._buildPath = typeof config.out === 'function' ? + 'FUNCTION' : config.out; + } + } else if (!config.cssIn) { + //Now set up the config for require to use the build area, and calculate the + //build file locations. Pass along any config info too. + baseConfig = { + baseUrl: config.dirBaseUrl, + paths: buildPaths + }; + + lang.mixin(baseConfig, config); + require(baseConfig); + + if (modules) { + modules.forEach(function (module) { + if (module.name) { + module._buildPath = buildContext.nameToUrl(module.name, null); + if (!module.create) { + file.copyFile(module._sourcePath, module._buildPath); + } + } + }); + } + } + + //Run CSS optimizations before doing JS module tracing, to allow + //things like text loader plugins loading CSS to get the optimized + //CSS. + if (config.optimizeCss && config.optimizeCss !== "none" && config.dir) { + buildFileContents += optimize.css(config.dir, config); + } + }).then(function() { + baseConfig = lang.deeplikeCopy(require.s.contexts._.config); + }).then(function () { + var actions = []; + + if (modules) { + actions = modules.map(function (module, i) { + return function () { + //Save off buildPath to module index in a hash for quicker + //lookup later. + config._buildPathToModuleIndex[file.normalize(module._buildPath)] = i; + + //Call require to calculate dependencies. + return build.traceDependencies(module, config, baseConfig) + .then(function (layer) { + module.layer = layer; + }); + }; + }); + + return prim.serial(actions); + } + }).then(function () { + var actions; + + if (modules) { + //Now build up shadow layers for anything that should be excluded. + //Do this after tracing dependencies for each module, in case one + //of those modules end up being one of the excluded values. + actions = modules.map(function (module) { + return function () { + if (module.exclude) { + module.excludeLayers = []; + return prim.serial(module.exclude.map(function (exclude, i) { + return function () { + //See if it is already in the list of modules. + //If not trace dependencies for it. + var found = build.findBuildModule(exclude, modules); + if (found) { + module.excludeLayers[i] = found; + } else { + return build.traceDependencies({name: exclude}, config, baseConfig) + .then(function (layer) { + module.excludeLayers[i] = { layer: layer }; + }); + } + }; + })); + } + }; + }); + + return prim.serial(actions); + } + }).then(function () { + if (modules) { + return prim.serial(modules.map(function (module) { + return function () { + if (module.exclude) { + //module.exclude is an array of module names. For each one, + //get the nested dependencies for it via a matching entry + //in the module.excludeLayers array. + module.exclude.forEach(function (excludeModule, i) { + var excludeLayer = module.excludeLayers[i].layer, + map = excludeLayer.buildFileToModule; + excludeLayer.buildFilePaths.forEach(function(filePath){ + build.removeModulePath(map[filePath], filePath, module.layer); + }); + }); + } + if (module.excludeShallow) { + //module.excludeShallow is an array of module names. + //shallow exclusions are just that module itself, and not + //its nested dependencies. + module.excludeShallow.forEach(function (excludeShallowModule) { + var path = getOwn(module.layer.buildPathMap, excludeShallowModule); + if (path) { + build.removeModulePath(excludeShallowModule, path, module.layer); + } + }); + } + + //Flatten them and collect the build output for each module. + return build.flattenModule(module, module.layer, config).then(function (builtModule) { + var finalText, baseName; + //Save it to a temp file for now, in case there are other layers that + //contain optimized content that should not be included in later + //layer optimizations. See issue #56. + if (module._buildPath === 'FUNCTION') { + module._buildText = builtModule.text; + module._buildSourceMap = builtModule.sourceMap; + } else { + finalText = builtModule.text; + if (builtModule.sourceMap) { + baseName = module._buildPath.split('/'); + baseName = baseName.pop(); + finalText += '\n//# sourceMappingURL=' + baseName + '.map'; + file.saveUtf8File(module._buildPath + '.map', builtModule.sourceMap); + } + file.saveUtf8File(module._buildPath + '-temp', finalText); + + } + buildFileContents += builtModule.buildText; + }); + }; + })); + } + }).then(function () { + var moduleName; + if (modules) { + //Now move the build layers to their final position. + modules.forEach(function (module) { + var finalPath = module._buildPath; + if (finalPath !== 'FUNCTION') { + if (file.exists(finalPath)) { + file.deleteFile(finalPath); + } + file.renameFile(finalPath + '-temp', finalPath); + + //And finally, if removeCombined is specified, remove + //any of the files that were used in this layer. + //Be sure not to remove other build layers. + if (config.removeCombined && !config.out) { + module.layer.buildFilePaths.forEach(function (path) { + var isLayer = modules.some(function (mod) { + return mod._buildPath === path; + }), + relPath = build.makeRelativeFilePath(config.dir, path); + + if (file.exists(path) && + // not a build layer target + !isLayer && + // not outside the build directory + relPath.indexOf('..') !== 0) { + file.deleteFile(path); + } + }); + } + } + + //Signal layer is done + if (config.onModuleBundleComplete) { + config.onModuleBundleComplete(module.onCompleteData); + } + }); + } + + //If removeCombined in play, remove any empty directories that + //may now exist because of its use + if (config.removeCombined && !config.out && config.dir) { + file.deleteEmptyDirs(config.dir); + } + + //Do other optimizations. + if (config.out && !config.cssIn) { + //Just need to worry about one JS file. + fileName = config.modules[0]._buildPath; + if (fileName === 'FUNCTION') { + config.modules[0]._buildText = optimize.js(fileName, + config.modules[0]._buildText, + null, + config); + } else { + optimize.jsFile(fileName, null, fileName, config); + } + } else if (!config.cssIn) { + //Normal optimizations across modules. + + //JS optimizations. + fileNames = file.getFilteredFileList(config.dir, /\.js$/, true); + fileNames.forEach(function (fileName) { + var cfg, override, moduleIndex; + + //Generate the module name from the config.dir root. + moduleName = fileName.replace(config.dir, ''); + //Get rid of the extension + moduleName = moduleName.substring(0, moduleName.length - 3); + + //If there is an override for a specific layer build module, + //and this file is that module, mix in the override for use + //by optimize.jsFile. + moduleIndex = getOwn(config._buildPathToModuleIndex, fileName); + //Normalize, since getOwn could have returned undefined + moduleIndex = moduleIndex === 0 || moduleIndex > 0 ? moduleIndex : -1; + + //Try to avoid extra work if the other files do not need to + //be read. Build layers should be processed at the very + //least for optimization. + if (moduleIndex > -1 || !config.skipDirOptimize || + config.normalizeDirDefines === "all" || + config.cjsTranslate) { + //Convert the file to transport format, but without a name + //inserted (by passing null for moduleName) since the files are + //standalone, one module per file. + fileContents = file.readFile(fileName); + + + //For builds, if wanting cjs translation, do it now, so that + //the individual modules can be loaded cross domain via + //plain script tags. + if (config.cjsTranslate && + (!config.shim || !lang.hasProp(config.shim, moduleName))) { + fileContents = commonJs.convert(fileName, fileContents); + } + + if (moduleIndex === -1) { + if (config.onBuildRead) { + fileContents = config.onBuildRead(moduleName, + fileName, + fileContents); + } + + //Only do transport normalization if this is not a build + //layer (since it was already normalized) and if + //normalizeDirDefines indicated all should be done. + if (config.normalizeDirDefines === "all") { + fileContents = build.toTransport(config.namespace, + null, + fileName, + fileContents); + } + + if (config.onBuildWrite) { + fileContents = config.onBuildWrite(moduleName, + fileName, + fileContents); + } + } + + override = moduleIndex > -1 ? + config.modules[moduleIndex].override : null; + if (override) { + cfg = build.createOverrideConfig(config, override); + } else { + cfg = config; + } + + if (moduleIndex > -1 || !config.skipDirOptimize) { + optimize.jsFile(fileName, fileContents, fileName, cfg, pluginCollector); + } + } + }); + + //Normalize all the plugin resources. + context = require.s.contexts._; + + for (moduleName in pluginCollector) { + if (hasProp(pluginCollector, moduleName)) { + parentModuleMap = context.makeModuleMap(moduleName); + resources = pluginCollector[moduleName]; + for (i = 0; i < resources.length; i++) { + resource = resources[i]; + moduleMap = context.makeModuleMap(resource, parentModuleMap); + if (falseProp(context.plugins, moduleMap.prefix)) { + //Set the value in context.plugins so it + //will be evaluated as a full plugin. + context.plugins[moduleMap.prefix] = true; + + //Do not bother if the plugin is not available. + if (!file.exists(require.toUrl(moduleMap.prefix + '.js'))) { + continue; + } + + //Rely on the require in the build environment + //to be synchronous + context.require([moduleMap.prefix]); + + //Now that the plugin is loaded, redo the moduleMap + //since the plugin will need to normalize part of the path. + moduleMap = context.makeModuleMap(resource, parentModuleMap); + } + + //Only bother with plugin resources that can be handled + //processed by the plugin, via support of the writeFile + //method. + if (falseProp(pluginProcessed, moduleMap.id)) { + //Only do the work if the plugin was really loaded. + //Using an internal access because the file may + //not really be loaded. + plugin = getOwn(context.defined, moduleMap.prefix); + if (plugin && plugin.writeFile) { + plugin.writeFile( + moduleMap.prefix, + moduleMap.name, + require, + makeWriteFile( + config.namespace + ), + context.config + ); + } + + pluginProcessed[moduleMap.id] = true; + } + } + + } + } + + //console.log('PLUGIN COLLECTOR: ' + JSON.stringify(pluginCollector, null, " ")); + + + //All module layers are done, write out the build.txt file. + file.saveUtf8File(config.dir + "build.txt", buildFileContents); + } + + //If just have one CSS file to optimize, do that here. + if (config.cssIn) { + buildFileContents += optimize.cssFile(config.cssIn, config.out, config).buildText; + } + + if (typeof config.out === 'function') { + config.out(config.modules[0]._buildText); + } + + //Print out what was built into which layers. + if (buildFileContents) { + logger.info(buildFileContents); + return buildFileContents; + } + + return ''; + }); + }; + + /** + * Converts command line args like "paths.foo=../some/path" + * result.paths = { foo: '../some/path' } where prop = paths, + * name = paths.foo and value = ../some/path, so it assumes the + * name=value splitting has already happened. + */ + function stringDotToObj(result, name, value) { + var parts = name.split('.'); + + parts.forEach(function (prop, i) { + if (i === parts.length - 1) { + result[prop] = value; + } else { + if (falseProp(result, prop)) { + result[prop] = {}; + } + result = result[prop]; + } + + }); + } + + build.objProps = { + paths: true, + wrap: true, + pragmas: true, + pragmasOnSave: true, + has: true, + hasOnSave: true, + uglify: true, + uglify2: true, + closure: true, + map: true, + throwWhen: true + }; + + build.hasDotPropMatch = function (prop) { + var dotProp, + index = prop.indexOf('.'); + + if (index !== -1) { + dotProp = prop.substring(0, index); + return hasProp(build.objProps, dotProp); + } + return false; + }; + + /** + * Converts an array that has String members of "name=value" + * into an object, where the properties on the object are the names in the array. + * Also converts the strings "true" and "false" to booleans for the values. + * member name/value pairs, and converts some comma-separated lists into + * arrays. + * @param {Array} ary + */ + build.convertArrayToObject = function (ary) { + var result = {}, i, separatorIndex, prop, value, + needArray = { + "include": true, + "exclude": true, + "excludeShallow": true, + "insertRequire": true, + "stubModules": true, + "deps": true + }; + + for (i = 0; i < ary.length; i++) { + separatorIndex = ary[i].indexOf("="); + if (separatorIndex === -1) { + throw "Malformed name/value pair: [" + ary[i] + "]. Format should be name=value"; + } + + value = ary[i].substring(separatorIndex + 1, ary[i].length); + if (value === "true") { + value = true; + } else if (value === "false") { + value = false; + } + + prop = ary[i].substring(0, separatorIndex); + + //Convert to array if necessary + if (getOwn(needArray, prop)) { + value = value.split(","); + } + + if (build.hasDotPropMatch(prop)) { + stringDotToObj(result, prop, value); + } else { + result[prop] = value; + } + } + return result; //Object + }; + + build.makeAbsPath = function (path, absFilePath) { + if (!absFilePath) { + return path; + } + + //Add abspath if necessary. If path starts with a slash or has a colon, + //then already is an abolute path. + if (path.indexOf('/') !== 0 && path.indexOf(':') === -1) { + path = absFilePath + + (absFilePath.charAt(absFilePath.length - 1) === '/' ? '' : '/') + + path; + path = file.normalize(path); + } + return path.replace(lang.backSlashRegExp, '/'); + }; + + build.makeAbsObject = function (props, obj, absFilePath) { + var i, prop; + if (obj) { + for (i = 0; i < props.length; i++) { + prop = props[i]; + if (hasProp(obj, prop) && typeof obj[prop] === 'string') { + obj[prop] = build.makeAbsPath(obj[prop], absFilePath); + } + } + } + }; + + /** + * For any path in a possible config, make it absolute relative + * to the absFilePath passed in. + */ + build.makeAbsConfig = function (config, absFilePath) { + var props, prop, i; + + props = ["appDir", "dir", "baseUrl"]; + for (i = 0; i < props.length; i++) { + prop = props[i]; + + if (getOwn(config, prop)) { + //Add abspath if necessary, make sure these paths end in + //slashes + if (prop === "baseUrl") { + config.originalBaseUrl = config.baseUrl; + if (config.appDir) { + //If baseUrl with an appDir, the baseUrl is relative to + //the appDir, *not* the absFilePath. appDir and dir are + //made absolute before baseUrl, so this will work. + config.baseUrl = build.makeAbsPath(config.originalBaseUrl, config.appDir); + } else { + //The dir output baseUrl is same as regular baseUrl, both + //relative to the absFilePath. + config.baseUrl = build.makeAbsPath(config[prop], absFilePath); + } + } else { + config[prop] = build.makeAbsPath(config[prop], absFilePath); + } + + config[prop] = endsWithSlash(config[prop]); + } + } + + build.makeAbsObject(["out", "cssIn"], config, absFilePath); + build.makeAbsObject(["startFile", "endFile"], config.wrap, absFilePath); + }; + + /** + * Creates a relative path to targetPath from refPath. + * Only deals with file paths, not folders. If folders, + * make sure paths end in a trailing '/'. + */ + build.makeRelativeFilePath = function (refPath, targetPath) { + var i, dotLength, finalParts, length, + refParts = refPath.split('/'), + targetParts = targetPath.split('/'), + //Pull off file name + targetName = targetParts.pop(), + dotParts = []; + + //Also pop off the ref file name to make the matches against + //targetParts equivalent. + refParts.pop(); + + length = refParts.length; + + for (i = 0; i < length; i += 1) { + if (refParts[i] !== targetParts[i]) { + break; + } + } + + //Now i is the index in which they diverge. + finalParts = targetParts.slice(i); + + dotLength = length - i; + for (i = 0; i > -1 && i < dotLength; i += 1) { + dotParts.push('..'); + } + + return dotParts.join('/') + (dotParts.length ? '/' : '') + + finalParts.join('/') + (finalParts.length ? '/' : '') + + targetName; + }; + + build.nestedMix = { + paths: true, + has: true, + hasOnSave: true, + pragmas: true, + pragmasOnSave: true + }; + + /** + * Mixes additional source config into target config, and merges some + * nested config, like paths, correctly. + */ + function mixConfig(target, source) { + var prop, value; + + for (prop in source) { + if (hasProp(source, prop)) { + //If the value of the property is a plain object, then + //allow a one-level-deep mixing of it. + value = source[prop]; + if (typeof value === 'object' && value && + !lang.isArray(value) && !lang.isFunction(value) && + !lang.isRegExp(value)) { + target[prop] = lang.mixin({}, target[prop], value, true); + } else { + target[prop] = value; + } + } + } + + //Set up log level since it can affect if errors are thrown + //or caught and passed to errbacks while doing config setup. + if (lang.hasProp(target, 'logLevel')) { + logger.logLevel(target.logLevel); + } + } + + /** + * Converts a wrap.startFile or endFile to be start/end as a string. + * the startFile/endFile values can be arrays. + */ + function flattenWrapFile(wrap, keyName, absFilePath) { + var keyFileName = keyName + 'File'; + + if (typeof wrap[keyName] !== 'string' && wrap[keyFileName]) { + wrap[keyName] = ''; + if (typeof wrap[keyFileName] === 'string') { + wrap[keyFileName] = [wrap[keyFileName]]; + } + wrap[keyFileName].forEach(function (fileName) { + wrap[keyName] += (wrap[keyName] ? '\n' : '') + + file.readFile(build.makeAbsPath(fileName, absFilePath)); + }); + } else if (wrap[keyName] === null || wrap[keyName] === undefined) { + //Allow missing one, just set to empty string. + wrap[keyName] = ''; + } else if (typeof wrap[keyName] !== 'string') { + throw new Error('wrap.' + keyName + ' or wrap.' + keyFileName + ' malformed'); + } + } + + function normalizeWrapConfig(config, absFilePath) { + //Get any wrap text. + try { + if (config.wrap) { + if (config.wrap === true) { + //Use default values. + config.wrap = { + start: '(function () {', + end: '}());' + }; + } else { + flattenWrapFile(config.wrap, 'start', absFilePath); + flattenWrapFile(config.wrap, 'end', absFilePath); + } + } + } catch (wrapError) { + throw new Error('Malformed wrap config: ' + wrapError.toString()); + } + } + + /** + * Creates a config object for an optimization build. + * It will also read the build profile if it is available, to create + * the configuration. + * + * @param {Object} cfg config options that take priority + * over defaults and ones in the build file. These options could + * be from a command line, for instance. + * + * @param {Object} the created config object. + */ + build.createConfig = function (cfg) { + /*jslint evil: true */ + var config = {}, buildFileContents, buildFileConfig, mainConfig, + mainConfigFile, mainConfigPath, buildFile, absFilePath; + + //Make sure all paths are relative to current directory. + absFilePath = file.absPath('.'); + build.makeAbsConfig(cfg, absFilePath); + build.makeAbsConfig(buildBaseConfig, absFilePath); + + lang.mixin(config, buildBaseConfig); + lang.mixin(config, cfg, true); + + //Set up log level early since it can affect if errors are thrown + //or caught and passed to errbacks, even while constructing config. + if (lang.hasProp(config, 'logLevel')) { + logger.logLevel(config.logLevel); + } + + if (config.buildFile) { + //A build file exists, load it to get more config. + buildFile = file.absPath(config.buildFile); + + //Find the build file, and make sure it exists, if this is a build + //that has a build profile, and not just command line args with an in=path + if (!file.exists(buildFile)) { + throw new Error("ERROR: build file does not exist: " + buildFile); + } + + absFilePath = config.baseUrl = file.absPath(file.parent(buildFile)); + + //Load build file options. + buildFileContents = file.readFile(buildFile); + try { + buildFileConfig = eval("(" + buildFileContents + ")"); + build.makeAbsConfig(buildFileConfig, absFilePath); + + //Mix in the config now so that items in mainConfigFile can + //be resolved relative to them if necessary, like if appDir + //is set here, but the baseUrl is in mainConfigFile. Will + //re-mix in the same build config later after mainConfigFile + //is processed, since build config should take priority. + mixConfig(config, buildFileConfig); + } catch (e) { + throw new Error("Build file " + buildFile + " is malformed: " + e); + } + } + + mainConfigFile = config.mainConfigFile || (buildFileConfig && buildFileConfig.mainConfigFile); + if (mainConfigFile) { + mainConfigFile = build.makeAbsPath(mainConfigFile, absFilePath); + if (!file.exists(mainConfigFile)) { + throw new Error(mainConfigFile + ' does not exist.'); + } + try { + mainConfig = parse.findConfig(file.readFile(mainConfigFile)).config; + } catch (configError) { + throw new Error('The config in mainConfigFile ' + + mainConfigFile + + ' cannot be used because it cannot be evaluated' + + ' correctly while running in the optimizer. Try only' + + ' using a config that is also valid JSON, or do not use' + + ' mainConfigFile and instead copy the config values needed' + + ' into a build file or command line arguments given to the optimizer.\n' + + 'Source error from parsing: ' + mainConfigFile + ': ' + configError); + } + if (mainConfig) { + mainConfigPath = mainConfigFile.substring(0, mainConfigFile.lastIndexOf('/')); + + //Add in some existing config, like appDir, since they can be + //used inside the mainConfigFile -- paths and baseUrl are + //relative to them. + if (config.appDir && !mainConfig.appDir) { + mainConfig.appDir = config.appDir; + } + + //If no baseUrl, then use the directory holding the main config. + if (!mainConfig.baseUrl) { + mainConfig.baseUrl = mainConfigPath; + } + + build.makeAbsConfig(mainConfig, mainConfigPath); + mixConfig(config, mainConfig); + } + } + + //Mix in build file config, but only after mainConfig has been mixed in. + if (buildFileConfig) { + mixConfig(config, buildFileConfig); + } + + //Re-apply the override config values. Command line + //args should take precedence over build file values. + mixConfig(config, cfg); + + //Fix paths to full paths so that they can be adjusted consistently + //lately to be in the output area. + lang.eachProp(config.paths, function (value, prop) { + if (lang.isArray(value)) { + throw new Error('paths fallback not supported in optimizer. ' + + 'Please provide a build config path override ' + + 'for ' + prop); + } + config.paths[prop] = build.makeAbsPath(value, config.baseUrl); + }); + + //Set final output dir + if (hasProp(config, "baseUrl")) { + if (config.appDir) { + config.dirBaseUrl = build.makeAbsPath(config.originalBaseUrl, config.dir); + } else { + config.dirBaseUrl = config.dir || config.baseUrl; + } + //Make sure dirBaseUrl ends in a slash, since it is + //concatenated with other strings. + config.dirBaseUrl = endsWithSlash(config.dirBaseUrl); + } + + //Check for errors in config + if (config.main) { + throw new Error('"main" passed as an option, but the ' + + 'supported option is called "name".'); + } + if (config.out && !config.name && !config.modules && !config.include && + !config.cssIn) { + throw new Error('Missing either a "name", "include" or "modules" ' + + 'option'); + } + if (config.cssIn) { + if (config.dir || config.appDir) { + throw new Error('cssIn is only for the output of single file ' + + 'CSS optimizations and is not compatible with "dir" or "appDir" configuration.'); + } + if (!config.out) { + throw new Error('"out" option missing.'); + } + } + if (!config.cssIn && !config.baseUrl) { + //Just use the current directory as the baseUrl + config.baseUrl = './'; + } + if (!config.out && !config.dir) { + throw new Error('Missing either an "out" or "dir" config value. ' + + 'If using "appDir" for a full project optimization, ' + + 'use "dir". If you want to optimize to one file, ' + + 'use "out".'); + } + if (config.appDir && config.out) { + throw new Error('"appDir" is not compatible with "out". Use "dir" ' + + 'instead. appDir is used to copy whole projects, ' + + 'where "out" with "baseUrl" is used to just ' + + 'optimize to one file.'); + } + if (config.out && config.dir) { + throw new Error('The "out" and "dir" options are incompatible.' + + ' Use "out" if you are targeting a single file for' + + ' for optimization, and "dir" if you want the appDir' + + ' or baseUrl directories optimized.'); + } + + if (config.dir) { + // Make sure the output dir is not set to a parent of the + // source dir or the same dir, as it will result in source + // code deletion. + if (config.dir === config.baseUrl || + config.dir === config.appDir || + (config.baseUrl && build.makeRelativeFilePath(config.dir, + config.baseUrl).indexOf('..') !== 0) || + (config.appDir && + build.makeRelativeFilePath(config.dir, config.appDir).indexOf('..') !== 0)) { + throw new Error('"dir" is set to a parent or same directory as' + + ' "appDir" or "baseUrl". This can result in' + + ' the deletion of source code. Stopping.'); + } + } + + if (config.insertRequire && !lang.isArray(config.insertRequire)) { + throw new Error('insertRequire should be a list of module IDs' + + ' to insert in to a require([]) call.'); + } + + if (config.generateSourceMaps) { + if (config.preserveLicenseComments && config.optimize !== 'none') { + throw new Error('Cannot use preserveLicenseComments and ' + + 'generateSourceMaps together. Either explcitly set ' + + 'preserveLicenseComments to false (default is true) or ' + + 'turn off generateSourceMaps. If you want source maps with ' + + 'license comments, see: ' + + 'http://requirejs.org/docs/errors.html#sourcemapcomments'); + } else if (config.optimize !== 'none' && + config.optimize !== 'closure' && + config.optimize !== 'uglify2') { + //Allow optimize: none to pass, since it is useful when toggling + //minification on and off to debug something, and it implicitly + //works, since it does not need a source map. + throw new Error('optimize: "' + config.optimize + + '" does not support generateSourceMaps.'); + } + } + + if ((config.name || config.include) && !config.modules) { + //Just need to build one file, but may be part of a whole appDir/ + //baseUrl copy, but specified on the command line, so cannot do + //the modules array setup. So create a modules section in that + //case. + config.modules = [ + { + name: config.name, + out: config.out, + create: config.create, + include: config.include, + exclude: config.exclude, + excludeShallow: config.excludeShallow, + insertRequire: config.insertRequire, + stubModules: config.stubModules + } + ]; + delete config.stubModules; + } else if (config.modules && config.out) { + throw new Error('If the "modules" option is used, then there ' + + 'should be a "dir" option set and "out" should ' + + 'not be used since "out" is only for single file ' + + 'optimization output.'); + } else if (config.modules && config.name) { + throw new Error('"name" and "modules" options are incompatible. ' + + 'Either use "name" if doing a single file ' + + 'optimization, or "modules" if you want to target ' + + 'more than one file for optimization.'); + } + + if (config.out && !config.cssIn) { + //Just one file to optimize. + + //Does not have a build file, so set up some defaults. + //Optimizing CSS should not be allowed, unless explicitly + //asked for on command line. In that case the only task is + //to optimize a CSS file. + if (!cfg.optimizeCss) { + config.optimizeCss = "none"; + } + } + + //Normalize cssPrefix + if (config.cssPrefix) { + //Make sure cssPrefix ends in a slash + config.cssPrefix = endsWithSlash(config.cssPrefix); + } else { + config.cssPrefix = ''; + } + + //Cycle through modules and combine any local stubModules with + //global values. + if (config.modules && config.modules.length) { + config.modules.forEach(function (mod) { + if (config.stubModules) { + mod.stubModules = config.stubModules.concat(mod.stubModules || []); + } + + //Create a hash lookup for the stubModules config to make lookup + //cheaper later. + if (mod.stubModules) { + mod.stubModules._byName = {}; + mod.stubModules.forEach(function (id) { + mod.stubModules._byName[id] = true; + }); + } + + //Allow wrap config in overrides, but normalize it. + if (mod.override) { + normalizeWrapConfig(mod.override, absFilePath); + } + }); + } + + normalizeWrapConfig(config, absFilePath); + + //Do final input verification + if (config.context) { + throw new Error('The build argument "context" is not supported' + + ' in a build. It should only be used in web' + + ' pages.'); + } + + //Set up normalizeDirDefines. If not explicitly set, if optimize "none", + //set to "skip" otherwise set to "all". + if (!hasProp(config, 'normalizeDirDefines')) { + if (config.optimize === 'none' || config.skipDirOptimize) { + config.normalizeDirDefines = 'skip'; + } else { + config.normalizeDirDefines = 'all'; + } + } + + //Set file.fileExclusionRegExp if desired + if (hasProp(config, 'fileExclusionRegExp')) { + if (typeof config.fileExclusionRegExp === "string") { + file.exclusionRegExp = new RegExp(config.fileExclusionRegExp); + } else { + file.exclusionRegExp = config.fileExclusionRegExp; + } + } else if (hasProp(config, 'dirExclusionRegExp')) { + //Set file.dirExclusionRegExp if desired, this is the old + //name for fileExclusionRegExp before 1.0.2. Support for backwards + //compatibility + file.exclusionRegExp = config.dirExclusionRegExp; + } + + //Remove things that may cause problems in the build. + delete config.jQuery; + delete config.enforceDefine; + delete config.urlArgs; + + return config; + }; + + /** + * finds the module being built/optimized with the given moduleName, + * or returns null. + * @param {String} moduleName + * @param {Array} modules + * @returns {Object} the module object from the build profile, or null. + */ + build.findBuildModule = function (moduleName, modules) { + var i, module; + for (i = 0; i < modules.length; i++) { + module = modules[i]; + if (module.name === moduleName) { + return module; + } + } + return null; + }; + + /** + * Removes a module name and path from a layer, if it is supposed to be + * excluded from the layer. + * @param {String} moduleName the name of the module + * @param {String} path the file path for the module + * @param {Object} layer the layer to remove the module/path from + */ + build.removeModulePath = function (module, path, layer) { + var index = layer.buildFilePaths.indexOf(path); + if (index !== -1) { + layer.buildFilePaths.splice(index, 1); + } + }; + + /** + * Uses the module build config object to trace the dependencies for the + * given module. + * + * @param {Object} module the module object from the build config info. + * @param {Object} config the build config object. + * @param {Object} [baseLoaderConfig] the base loader config to use for env resets. + * + * @returns {Object} layer information about what paths and modules should + * be in the flattened module. + */ + build.traceDependencies = function (module, config, baseLoaderConfig) { + var include, override, layer, context, oldContext, + rawTextByIds, + syncChecks = { + rhino: true, + node: true, + xpconnect: true + }, + deferred = prim(); + + //Reset some state set up in requirePatch.js, and clean up require's + //current context. + oldContext = require._buildReset(); + + //Grab the reset layer and context after the reset, but keep the + //old config to reuse in the new context. + layer = require._layer; + context = layer.context; + + //Put back basic config, use a fresh object for it. + if (baseLoaderConfig) { + require(lang.deeplikeCopy(baseLoaderConfig)); + } + + logger.trace("\nTracing dependencies for: " + (module.name || + (typeof module.out === 'function' ? 'FUNCTION' : module.out))); + include = module.name && !module.create ? [module.name] : []; + if (module.include) { + include = include.concat(module.include); + } + + //If there are overrides to basic config, set that up now.; + if (module.override) { + if (baseLoaderConfig) { + override = build.createOverrideConfig(baseLoaderConfig, module.override); + } else { + override = lang.deeplikeCopy(module.override); + } + require(override); + } + + //Now, populate the rawText cache with any values explicitly passed in + //via config. + rawTextByIds = require.s.contexts._.config.rawText; + if (rawTextByIds) { + lang.eachProp(rawTextByIds, function (contents, id) { + var url = require.toUrl(id) + '.js'; + require._cachedRawText[url] = contents; + }); + } + + + //Configure the callbacks to be called. + deferred.reject.__requireJsBuild = true; + + //Use a wrapping function so can check for errors. + function includeFinished(value) { + //If a sync build environment, check for errors here, instead of + //in the then callback below, since some errors, like two IDs pointed + //to same URL but only one anon ID will leave the loader in an + //unresolved state since a setTimeout cannot be used to check for + //timeout. + var hasError = false; + if (syncChecks[env.get()]) { + try { + build.checkForErrors(context); + } catch (e) { + hasError = true; + deferred.reject(e); + } + } + + if (!hasError) { + deferred.resolve(value); + } + } + includeFinished.__requireJsBuild = true; + + //Figure out module layer dependencies by calling require to do the work. + require(include, includeFinished, deferred.reject); + + // If a sync env, then with the "two IDs to same anon module path" + // issue, the require never completes, need to check for errors + // here. + if (syncChecks[env.get()]) { + build.checkForErrors(context); + } + + return deferred.promise.then(function () { + //Reset config + if (module.override && baseLoaderConfig) { + require(lang.deeplikeCopy(baseLoaderConfig)); + } + + build.checkForErrors(context); + + return layer; + }); + }; + + build.checkForErrors = function (context) { + //Check to see if it all loaded. If not, then throw, and give + //a message on what is left. + var id, prop, mod, idParts, pluginId, + errMessage = '', + failedPluginMap = {}, + failedPluginIds = [], + errIds = [], + errUrlMap = {}, + errUrlConflicts = {}, + hasErrUrl = false, + hasUndefined = false, + defined = context.defined, + registry = context.registry; + + function populateErrUrlMap(id, errUrl, skipNew) { + if (!skipNew) { + errIds.push(id); + } + + if (errUrlMap[errUrl]) { + hasErrUrl = true; + //This error module has the same URL as another + //error module, could be misconfiguration. + if (!errUrlConflicts[errUrl]) { + errUrlConflicts[errUrl] = []; + //Store the original module that had the same URL. + errUrlConflicts[errUrl].push(errUrlMap[errUrl]); + } + errUrlConflicts[errUrl].push(id); + } else if (!skipNew) { + errUrlMap[errUrl] = id; + } + } + + for (id in registry) { + if (hasProp(registry, id) && id.indexOf('_@r') !== 0) { + hasUndefined = true; + mod = getOwn(registry, id); + + if (id.indexOf('_unnormalized') === -1 && mod && mod.enabled) { + populateErrUrlMap(id, mod.map.url); + } + + //Look for plugins that did not call load() + idParts = id.split('!'); + pluginId = idParts[0]; + if (idParts.length > 1 && falseProp(failedPluginMap, pluginId)) { + failedPluginIds.push(pluginId); + failedPluginMap[pluginId] = true; + } + } + } + + // If have some modules that are not defined/stuck in the registry, + // then check defined modules for URL overlap. + if (hasUndefined) { + for (id in defined) { + if (hasProp(defined, id) && id.indexOf('!') === -1) { + populateErrUrlMap(id, require.toUrl(id) + '.js', true); + } + } + } + + if (errIds.length || failedPluginIds.length) { + if (failedPluginIds.length) { + errMessage += 'Loader plugin' + + (failedPluginIds.length === 1 ? '' : 's') + + ' did not call ' + + 'the load callback in the build: ' + + failedPluginIds.join(', ') + '\n'; + } + errMessage += 'Module loading did not complete for: ' + errIds.join(', '); + + if (hasErrUrl) { + errMessage += '\nThe following modules share the same URL. This ' + + 'could be a misconfiguration if that URL only has ' + + 'one anonymous module in it:'; + for (prop in errUrlConflicts) { + if (hasProp(errUrlConflicts, prop)) { + errMessage += '\n' + prop + ': ' + + errUrlConflicts[prop].join(', '); + } + } + } + throw new Error(errMessage); + } + }; + + build.createOverrideConfig = function (config, override) { + var cfg = lang.deeplikeCopy(config), + oride = lang.deeplikeCopy(override); + + lang.eachProp(oride, function (value, prop) { + if (hasProp(build.objProps, prop)) { + //An object property, merge keys. Start a new object + //so that source object in config does not get modified. + cfg[prop] = {}; + lang.mixin(cfg[prop], config[prop], true); + lang.mixin(cfg[prop], override[prop], true); + } else { + cfg[prop] = override[prop]; + } + }); + + return cfg; + }; + + /** + * Uses the module build config object to create an flattened version + * of the module, with deep dependencies included. + * + * @param {Object} module the module object from the build config info. + * + * @param {Object} layer the layer object returned from build.traceDependencies. + * + * @param {Object} the build config object. + * + * @returns {Object} with two properties: "text", the text of the flattened + * module, and "buildText", a string of text representing which files were + * included in the flattened module text. + */ + build.flattenModule = function (module, layer, config) { + var fileContents, sourceMapGenerator, + sourceMapBase, + buildFileContents = ''; + + return prim().start(function () { + var reqIndex, currContents, + moduleName, shim, packageConfig, nonPackageName, + parts, builder, writeApi, + namespace, namespaceWithDot, stubModulesByName, + context = layer.context, + onLayerEnds = [], + onLayerEndAdded = {}; + + //Use override settings, particularly for pragmas + //Do this before the var readings since it reads config values. + if (module.override) { + config = build.createOverrideConfig(config, module.override); + } + + namespace = config.namespace || ''; + namespaceWithDot = namespace ? namespace + '.' : ''; + stubModulesByName = (module.stubModules && module.stubModules._byName) || {}; + + //Start build output for the module. + module.onCompleteData = { + name: module.name, + path: (config.dir ? module._buildPath.replace(config.dir, "") : module._buildPath), + included: [] + }; + + buildFileContents += "\n" + + module.onCompleteData.path + + "\n----------------\n"; + + //If there was an existing file with require in it, hoist to the top. + if (layer.existingRequireUrl) { + reqIndex = layer.buildFilePaths.indexOf(layer.existingRequireUrl); + if (reqIndex !== -1) { + layer.buildFilePaths.splice(reqIndex, 1); + layer.buildFilePaths.unshift(layer.existingRequireUrl); + } + } + + if (config.generateSourceMaps) { + sourceMapBase = config.dir || config.baseUrl; + sourceMapGenerator = new SourceMapGenerator.SourceMapGenerator({ + file: module._buildPath.replace(sourceMapBase, '') + }); + } + + //Write the built module to disk, and build up the build output. + fileContents = ""; + return prim.serial(layer.buildFilePaths.map(function (path) { + return function () { + var lineCount, + singleContents = ''; + + moduleName = layer.buildFileToModule[path]; + //If the moduleName is for a package main, then update it to the + //real main value. + packageConfig = layer.context.config.pkgs && + getOwn(layer.context.config.pkgs, moduleName); + if (packageConfig) { + nonPackageName = moduleName; + moduleName += '/' + packageConfig.main; + } + + return prim().start(function () { + //Figure out if the module is a result of a build plugin, and if so, + //then delegate to that plugin. + parts = context.makeModuleMap(moduleName); + builder = parts.prefix && getOwn(context.defined, parts.prefix); + if (builder) { + if (builder.onLayerEnd && falseProp(onLayerEndAdded, parts.prefix)) { + onLayerEnds.push(builder); + onLayerEndAdded[parts.prefix] = true; + } + + if (builder.write) { + writeApi = function (input) { + singleContents += "\n" + addSemiColon(input, config); + if (config.onBuildWrite) { + singleContents = config.onBuildWrite(moduleName, path, singleContents); + } + }; + writeApi.asModule = function (moduleName, input) { + singleContents += "\n" + + addSemiColon(build.toTransport(namespace, moduleName, path, input, layer, { + useSourceUrl: layer.context.config.useSourceUrl + }), config); + if (config.onBuildWrite) { + singleContents = config.onBuildWrite(moduleName, path, singleContents); + } + }; + builder.write(parts.prefix, parts.name, writeApi); + } + return; + } else { + return prim().start(function () { + if (hasProp(stubModulesByName, moduleName)) { + //Just want to insert a simple module definition instead + //of the source module. Useful for plugins that inline + //all their resources. + if (hasProp(layer.context.plugins, moduleName)) { + //Slightly different content for plugins, to indicate + //that dynamic loading will not work. + return 'define({load: function(id){throw new Error("Dynamic load not allowed: " + id);}});'; + } else { + return 'define({});'; + } + } else { + return require._cacheReadAsync(path); + } + }).then(function (text) { + var hasPackageName; + + currContents = text; + + if (config.cjsTranslate && + (!config.shim || !lang.hasProp(config.shim, moduleName))) { + currContents = commonJs.convert(path, currContents); + } + + if (config.onBuildRead) { + currContents = config.onBuildRead(moduleName, path, currContents); + } + + if (packageConfig) { + hasPackageName = (nonPackageName === parse.getNamedDefine(currContents)); + } + + if (namespace) { + currContents = pragma.namespace(currContents, namespace); + } + + currContents = build.toTransport(namespace, moduleName, path, currContents, layer, { + useSourceUrl: config.useSourceUrl + }); + + if (packageConfig && !hasPackageName) { + currContents = addSemiColon(currContents, config) + '\n'; + currContents += namespaceWithDot + "define('" + + packageConfig.name + "', ['" + moduleName + + "'], function (main) { return main; });\n"; + } + + if (config.onBuildWrite) { + currContents = config.onBuildWrite(moduleName, path, currContents); + } + + //Semicolon is for files that are not well formed when + //concatenated with other content. + singleContents += "\n" + addSemiColon(currContents, config); + }); + } + }).then(function () { + var refPath, pluginId, resourcePath, + sourceMapPath, sourceMapLineNumber, + shortPath = path.replace(config.dir, ""); + + module.onCompleteData.included.push(shortPath); + buildFileContents += shortPath + "\n"; + + //Some files may not have declared a require module, and if so, + //put in a placeholder call so the require does not try to load them + //after the module is processed. + //If we have a name, but no defined module, then add in the placeholder. + if (moduleName && falseProp(layer.modulesWithNames, moduleName) && !config.skipModuleInsertion) { + shim = config.shim && (getOwn(config.shim, moduleName) || (packageConfig && getOwn(config.shim, nonPackageName))); + if (shim) { + singleContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", ' + + (shim.deps && shim.deps.length ? + build.makeJsArrayString(shim.deps) + ', ' : '') + + (shim.exportsFn ? shim.exportsFn() : 'function(){}') + + ');\n'; + } else { + singleContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", function(){});\n'; + } + } + + //Add to the source map + if (sourceMapGenerator) { + refPath = config.out ? config.baseUrl : module._buildPath; + parts = path.split('!'); + if (parts.length === 1) { + //Not a plugin resource, fix the path + sourceMapPath = build.makeRelativeFilePath(refPath, path); + } else { + //Plugin resource. If it looks like just a plugin + //followed by a module ID, pull off the plugin + //and put it at the end of the name, otherwise + //just leave it alone. + pluginId = parts.shift(); + resourcePath = parts.join('!'); + if (resourceIsModuleIdRegExp.test(resourcePath)) { + sourceMapPath = build.makeRelativeFilePath(refPath, require.toUrl(resourcePath)) + + '!' + pluginId; + } else { + sourceMapPath = path; + } + } + + sourceMapLineNumber = fileContents.split('\n').length - 1; + lineCount = singleContents.split('\n').length; + for (var i = 1; i <= lineCount; i += 1) { + sourceMapGenerator.addMapping({ + generated: { + line: sourceMapLineNumber + i, + column: 0 + }, + original: { + line: i, + column: 0 + }, + source: sourceMapPath + }); + } + + //Store the content of the original in the source + //map since other transforms later like minification + //can mess up translating back to the original + //source. + sourceMapGenerator.setSourceContent(sourceMapPath, singleContents); + } + + //Add the file to the final contents + fileContents += singleContents; + }); + }; + })).then(function () { + if (onLayerEnds.length) { + onLayerEnds.forEach(function (builder) { + var path; + if (typeof module.out === 'string') { + path = module.out; + } else if (typeof module._buildPath === 'string') { + path = module._buildPath; + } + builder.onLayerEnd(function (input) { + fileContents += "\n" + addSemiColon(input, config); + }, { + name: module.name, + path: path + }); + }); + } + + if (module.create) { + //The ID is for a created layer. Write out + //a module definition for it in case the + //built file is used with enforceDefine + //(#432) + fileContents += '\n' + namespaceWithDot + 'define("' + module.name + '", function(){});\n'; + } + + //Add a require at the end to kick start module execution, if that + //was desired. Usually this is only specified when using small shim + //loaders like almond. + if (module.insertRequire) { + fileContents += '\n' + namespaceWithDot + 'require(["' + module.insertRequire.join('", "') + '"]);\n'; + } + }); + }).then(function () { + return { + text: config.wrap ? + config.wrap.start + fileContents + config.wrap.end : + fileContents, + buildText: buildFileContents, + sourceMap: sourceMapGenerator ? + JSON.stringify(sourceMapGenerator.toJSON(), null, ' ') : + undefined + }; + }); + }; + + //Converts an JS array of strings to a string representation. + //Not using JSON.stringify() for Rhino's sake. + build.makeJsArrayString = function (ary) { + return '["' + ary.map(function (item) { + //Escape any double quotes, backslashes + return lang.jsEscape(item); + }).join('","') + '"]'; + }; + + build.toTransport = function (namespace, moduleName, path, contents, layer, options) { + var baseUrl = layer && layer.context.config.baseUrl; + + function onFound(info) { + //Only mark this module as having a name if not a named module, + //or if a named module and the name matches expectations. + if (layer && (info.needsId || info.foundId === moduleName)) { + layer.modulesWithNames[moduleName] = true; + } + } + + //Convert path to be a local one to the baseUrl, useful for + //useSourceUrl. + if (baseUrl) { + path = path.replace(baseUrl, ''); + } + + return transform.toTransport(namespace, moduleName, path, contents, onFound, options); + }; + + return build; +}); + + } + + + /** + * Sets the default baseUrl for requirejs to be directory of top level + * script. + */ + function setBaseUrl(fileName) { + //Use the file name's directory as the baseUrl if available. + dir = fileName.replace(/\\/g, '/'); + if (dir.indexOf('/') !== -1) { + dir = dir.split('/'); + dir.pop(); + dir = dir.join('/'); + //Make sure dir is JS-escaped, since it will be part of a JS string. + exec("require({baseUrl: '" + dir.replace(/[\\"']/g, '\\$&') + "'});"); + } + } + + function createRjsApi() { + //Create a method that will run the optimzer given an object + //config. + requirejs.optimize = function (config, callback, errback) { + if (!loadedOptimizedLib) { + loadLib(); + loadedOptimizedLib = true; + } + + //Create the function that will be called once build modules + //have been loaded. + var runBuild = function (build, logger, quit) { + //Make sure config has a log level, and if not, + //make it "silent" by default. + config.logLevel = config.hasOwnProperty('logLevel') ? + config.logLevel : logger.SILENT; + + //Reset build internals first in case this is part + //of a long-running server process that could have + //exceptioned out in a bad state. It is only defined + //after the first call though. + if (requirejs._buildReset) { + requirejs._buildReset(); + requirejs._cacheReset(); + } + + function done(result) { + //And clean up, in case something else triggers + //a build in another pathway. + if (requirejs._buildReset) { + requirejs._buildReset(); + requirejs._cacheReset(); + } + + // Ensure errors get propagated to the errback + if (result instanceof Error) { + throw result; + } + + return result; + } + + errback = errback || function (err) { + // Using console here since logger may have + // turned off error logging. Since quit is + // called want to be sure a message is printed. + console.log(err); + quit(1); + }; + + build(config).then(done, done).then(callback, errback); + }; + + requirejs({ + context: 'build' + }, ['build', 'logger', 'env!env/quit'], runBuild); + }; + + requirejs.tools = { + useLib: function (contextName, callback) { + if (!callback) { + callback = contextName; + contextName = 'uselib'; + } + + if (!useLibLoaded[contextName]) { + loadLib(); + useLibLoaded[contextName] = true; + } + + var req = requirejs({ + context: contextName + }); + + req(['build'], function () { + callback(req); + }); + } + }; + + requirejs.define = define; + } + + //If in Node, and included via a require('requirejs'), just export and + //THROW IT ON THE GROUND! + if (env === 'node' && reqMain !== module) { + setBaseUrl(path.resolve(reqMain ? reqMain.filename : '.')); + + createRjsApi(); + + module.exports = requirejs; + return; + } else if (env === 'browser') { + //Only option is to use the API. + setBaseUrl(location.href); + createRjsApi(); + return; + } else if ((env === 'rhino' || env === 'xpconnect') && + //User sets up requirejsAsLib variable to indicate it is loaded + //via load() to be used as a library. + typeof requirejsAsLib !== 'undefined' && requirejsAsLib) { + //This script is loaded via rhino's load() method, expose the + //API and get out. + setBaseUrl(fileName); + createRjsApi(); + return; + } + + if (commandOption === 'o') { + //Do the optimizer work. + loadLib(); + + /** + * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ + +/* + * Create a build.js file that has the build options you want and pass that + * build file to this file to do the build. See example.build.js for more information. + */ + +/*jslint strict: false, nomen: false */ +/*global require: false */ + +require({ + baseUrl: require.s.contexts._.config.baseUrl, + //Use a separate context than the default context so that the + //build can use the default context. + context: 'build', + catchError: { + define: true + } +}, ['env!env/args', 'env!env/quit', 'logger', 'build'], +function (args, quit, logger, build) { + build(args).then(function () {}, function (err) { + logger.error(err); + quit(1); + }); +}); + + + } else if (commandOption === 'v') { + console.log('r.js: ' + version + + ', RequireJS: ' + this.requirejsVars.require.version + + ', UglifyJS2: 2.4.0, UglifyJS: 1.3.4'); + } else if (commandOption === 'convert') { + loadLib(); + + this.requirejsVars.require(['env!env/args', 'commonJs', 'env!env/print'], + function (args, commonJs, print) { + + var srcDir, outDir; + srcDir = args[0]; + outDir = args[1]; + + if (!srcDir || !outDir) { + print('Usage: path/to/commonjs/modules output/dir'); + return; + } + + commonJs.convertDir(args[0], args[1]); + }); + } else { + //Just run an app + + //Load the bundled libraries for use in the app. + if (commandOption === 'lib') { + loadLib(); + } + + setBaseUrl(fileName); + + if (exists(fileName)) { + exec(readFile(fileName), fileName); + } else { + showHelp(); + } + } + +}((typeof console !== 'undefined' ? console : undefined), + (typeof Packages !== 'undefined' || (typeof window === 'undefined' && + typeof Components !== 'undefined' && Components.interfaces) ? + Array.prototype.slice.call(arguments, 0) : []), + (typeof readFile !== 'undefined' ? readFile : undefined))); diff --git a/node_modules/requirejs/package.json b/node_modules/requirejs/package.json new file mode 100644 index 00000000..932c4b0a --- /dev/null +++ b/node_modules/requirejs/package.json @@ -0,0 +1,39 @@ +{ + "name": "requirejs", + "description": "Node adapter for RequireJS, for loading AMD modules. Includes RequireJS optimizer", + "version": "2.1.9", + "homepage": "http://github.com/jrburke/r.js", + "author": { + "name": "James Burke", + "email": "jrburke@gmail.com", + "url": "http://github.com/jrburke" + }, + "licenses": [ + { + "type": "BSD", + "url": "https://github.com/jrburke/r.js/blob/master/LICENSE" + }, + { + "type": "MIT", + "url": "https://github.com/jrburke/r.js/blob/master/LICENSE" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/jrburke/r.js.git" + }, + "main": "./bin/r.js", + "bin": { + "r.js": "./bin/r.js" + }, + "engines": { + "node": ">=0.4.0" + }, + "readme": "# requirejs\n\nRequireJS for use in Node. includes:\n\n* r.js: the RequireJS optimizer, and AMD runtime for use in Node.\n* require.js: The browser-based AMD loader.\n\nMore information at http://requirejs.org\n\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/jrburke/r.js/issues" + }, + "_id": "requirejs@2.1.9", + "_from": "requirejs@~2.1" +} diff --git a/node_modules/requirejs/require.js b/node_modules/requirejs/require.js new file mode 100644 index 00000000..2ce09b5e --- /dev/null +++ b/node_modules/requirejs/require.js @@ -0,0 +1,2054 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +//Not using strict: uneven strict support in browsers, #392, and causes +//problems with requirejs.exec()/transpiler plugins that may not be strict. +/*jslint regexp: true, nomen: true, sloppy: true */ +/*global window, navigator, document, importScripts, setTimeout, opera */ + +var requirejs, require, define; +(function (global) { + var req, s, head, baseElement, dataMain, src, + interactiveScript, currentlyAddingScript, mainScript, subPath, + version = '2.1.9', + commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, + cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, + jsSuffixRegExp = /\.js$/, + currDirRegExp = /^\.\//, + op = Object.prototype, + ostring = op.toString, + hasOwn = op.hasOwnProperty, + ap = Array.prototype, + apsp = ap.splice, + isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document), + isWebWorker = !isBrowser && typeof importScripts !== 'undefined', + //PS3 indicates loaded and complete, but need to wait for complete + //specifically. Sequence is 'loading', 'loaded', execution, + // then 'complete'. The UA check is unfortunate, but not sure how + //to feature test w/o causing perf issues. + readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? + /^complete$/ : /^(complete|loaded)$/, + defContextName = '_', + //Oh the tragedy, detecting opera. See the usage of isOpera for reason. + isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', + contexts = {}, + cfg = {}, + globalDefQueue = [], + useInteractive = false; + + function isFunction(it) { + return ostring.call(it) === '[object Function]'; + } + + function isArray(it) { + return ostring.call(it) === '[object Array]'; + } + + /** + * Helper function for iterating over an array. If the func returns + * a true value, it will break out of the loop. + */ + function each(ary, func) { + if (ary) { + var i; + for (i = 0; i < ary.length; i += 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + /** + * Helper function for iterating over an array backwards. If the func + * returns a true value, it will break out of the loop. + */ + function eachReverse(ary, func) { + if (ary) { + var i; + for (i = ary.length - 1; i > -1; i -= 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + function getOwn(obj, prop) { + return hasProp(obj, prop) && obj[prop]; + } + + /** + * Cycles over properties in an object and calls a function for each + * property value. If the function returns a truthy value, then the + * iteration is stopped. + */ + function eachProp(obj, func) { + var prop; + for (prop in obj) { + if (hasProp(obj, prop)) { + if (func(obj[prop], prop)) { + break; + } + } + } + } + + /** + * Simple function to mix in properties from source into target, + * but only if target does not already have a property of the same name. + */ + function mixin(target, source, force, deepStringMixin) { + if (source) { + eachProp(source, function (value, prop) { + if (force || !hasProp(target, prop)) { + if (deepStringMixin && typeof value !== 'string') { + if (!target[prop]) { + target[prop] = {}; + } + mixin(target[prop], value, force, deepStringMixin); + } else { + target[prop] = value; + } + } + }); + } + return target; + } + + //Similar to Function.prototype.bind, but the 'this' object is specified + //first, since it is easier to read/figure out what 'this' will be. + function bind(obj, fn) { + return function () { + return fn.apply(obj, arguments); + }; + } + + function scripts() { + return document.getElementsByTagName('script'); + } + + function defaultOnError(err) { + throw err; + } + + //Allow getting a global that expressed in + //dot notation, like 'a.b.c'. + function getGlobal(value) { + if (!value) { + return value; + } + var g = global; + each(value.split('.'), function (part) { + g = g[part]; + }); + return g; + } + + /** + * Constructs an error with a pointer to an URL with more information. + * @param {String} id the error ID that maps to an ID on a web page. + * @param {String} message human readable error. + * @param {Error} [err] the original error, if there is one. + * + * @returns {Error} + */ + function makeError(id, msg, err, requireModules) { + var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); + e.requireType = id; + e.requireModules = requireModules; + if (err) { + e.originalError = err; + } + return e; + } + + if (typeof define !== 'undefined') { + //If a define is already in play via another AMD loader, + //do not overwrite. + return; + } + + if (typeof requirejs !== 'undefined') { + if (isFunction(requirejs)) { + //Do not overwrite and existing requirejs instance. + return; + } + cfg = requirejs; + requirejs = undefined; + } + + //Allow for a require config object + if (typeof require !== 'undefined' && !isFunction(require)) { + //assume it is a config object. + cfg = require; + require = undefined; + } + + function newContext(contextName) { + var inCheckLoaded, Module, context, handlers, + checkLoadedTimeoutId, + config = { + //Defaults. Do not set a default for map + //config to speed up normalize(), which + //will run faster if there is no default. + waitSeconds: 7, + baseUrl: './', + paths: {}, + pkgs: {}, + shim: {}, + config: {} + }, + registry = {}, + //registry of just enabled modules, to speed + //cycle breaking code when lots of modules + //are registered, but not activated. + enabledRegistry = {}, + undefEvents = {}, + defQueue = [], + defined = {}, + urlFetched = {}, + requireCounter = 1, + unnormalizedCounter = 1; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; ary[i]; i += 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @param {Boolean} applyMap apply the map config to the value. Should + * only be done if this normalization is for a dependency ID. + * @returns {String} normalized name + */ + function normalize(name, baseName, applyMap) { + var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment, + foundMap, foundI, foundStarMap, starI, + baseParts = baseName && baseName.split('/'), + normalizedBaseParts = baseParts, + map = config.map, + starMap = map && map['*']; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + if (getOwn(config.pkgs, baseName)) { + //If the baseName is a package name, then just treat it as one + //name to concat the name with. + normalizedBaseParts = baseParts = [baseName]; + } else { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + } + + name = normalizedBaseParts.concat(name.split('/')); + trimDots(name); + + //Some use of packages may use a . path to reference the + //'main' module name, so normalize for that. + pkgConfig = getOwn(config.pkgs, (pkgName = name[0])); + name = name.join('/'); + if (pkgConfig && name === pkgName + '/' + pkgConfig.main) { + name = pkgName; + } + } else if (name.indexOf('./') === 0) { + // No baseName, so this is ID is resolved relative + // to baseUrl, pull off the leading dot. + name = name.substring(2); + } + } + + //Apply map config if available. + if (applyMap && map && (baseParts || starMap)) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join('/'); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = getOwn(map, baseParts.slice(0, j).join('/')); + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = getOwn(mapValue, nameSegment); + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) { + foundStarMap = getOwn(starMap, nameSegment); + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function removeScript(name) { + if (isBrowser) { + each(scripts(), function (scriptNode) { + if (scriptNode.getAttribute('data-requiremodule') === name && + scriptNode.getAttribute('data-requirecontext') === context.contextName) { + scriptNode.parentNode.removeChild(scriptNode); + return true; + } + }); + } + } + + function hasPathFallback(id) { + var pathConfig = getOwn(config.paths, id); + if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { + //Pop off the first array value, since it failed, and + //retry + pathConfig.shift(); + context.require.undef(id); + context.require([id]); + return true; + } + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + /** + * Creates a module mapping that includes plugin prefix, module + * name, and path. If parentModuleMap is provided it will + * also normalize the name via require.normalize() + * + * @param {String} name the module name + * @param {String} [parentModuleMap] parent module map + * for the module name, used to resolve relative names. + * @param {Boolean} isNormalized: is the ID already normalized. + * This is true if this call is done for a define() module ID. + * @param {Boolean} applyMap: apply the map config to the ID. + * Should only be true if this map is for a dependency. + * + * @returns {Object} + */ + function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { + var url, pluginModule, suffix, nameParts, + prefix = null, + parentName = parentModuleMap ? parentModuleMap.name : null, + originalName = name, + isDefine = true, + normalizedName = ''; + + //If no name, then it means it is a require call, generate an + //internal name. + if (!name) { + isDefine = false; + name = '_@r' + (requireCounter += 1); + } + + nameParts = splitPrefix(name); + prefix = nameParts[0]; + name = nameParts[1]; + + if (prefix) { + prefix = normalize(prefix, parentName, applyMap); + pluginModule = getOwn(defined, prefix); + } + + //Account for relative paths if there is a base name. + if (name) { + if (prefix) { + if (pluginModule && pluginModule.normalize) { + //Plugin is loaded, use its normalize method. + normalizedName = pluginModule.normalize(name, function (name) { + return normalize(name, parentName, applyMap); + }); + } else { + normalizedName = normalize(name, parentName, applyMap); + } + } else { + //A regular module. + normalizedName = normalize(name, parentName, applyMap); + + //Normalized name may be a plugin ID due to map config + //application in normalize. The map config values must + //already be normalized, so do not need to redo that part. + nameParts = splitPrefix(normalizedName); + prefix = nameParts[0]; + normalizedName = nameParts[1]; + isNormalized = true; + + url = context.nameToUrl(normalizedName); + } + } + + //If the id is a plugin id that cannot be determined if it needs + //normalization, stamp it with a unique ID so two matching relative + //ids that may conflict can be separate. + suffix = prefix && !pluginModule && !isNormalized ? + '_unnormalized' + (unnormalizedCounter += 1) : + ''; + + return { + prefix: prefix, + name: normalizedName, + parentMap: parentModuleMap, + unnormalized: !!suffix, + url: url, + originalName: originalName, + isDefine: isDefine, + id: (prefix ? + prefix + '!' + normalizedName : + normalizedName) + suffix + }; + } + + function getModule(depMap) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (!mod) { + mod = registry[id] = new context.Module(depMap); + } + + return mod; + } + + function on(depMap, name, fn) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (hasProp(defined, id) && + (!mod || mod.defineEmitComplete)) { + if (name === 'defined') { + fn(defined[id]); + } + } else { + mod = getModule(depMap); + if (mod.error && name === 'error') { + fn(mod.error); + } else { + mod.on(name, fn); + } + } + } + + function onError(err, errback) { + var ids = err.requireModules, + notified = false; + + if (errback) { + errback(err); + } else { + each(ids, function (id) { + var mod = getOwn(registry, id); + if (mod) { + //Set error on module, so it skips timeout checks. + mod.error = err; + if (mod.events.error) { + notified = true; + mod.emit('error', err); + } + } + }); + + if (!notified) { + req.onError(err); + } + } + } + + /** + * Internal method to transfer globalQueue items to this context's + * defQueue. + */ + function takeGlobalQueue() { + //Push all the globalDefQueue items into the context's defQueue + if (globalDefQueue.length) { + //Array splice in the values since the context code has a + //local var ref to defQueue, so cannot just reassign the one + //on context. + apsp.apply(defQueue, + [defQueue.length - 1, 0].concat(globalDefQueue)); + globalDefQueue = []; + } + } + + handlers = { + 'require': function (mod) { + if (mod.require) { + return mod.require; + } else { + return (mod.require = context.makeRequire(mod.map)); + } + }, + 'exports': function (mod) { + mod.usingExports = true; + if (mod.map.isDefine) { + if (mod.exports) { + return mod.exports; + } else { + return (mod.exports = defined[mod.map.id] = {}); + } + } + }, + 'module': function (mod) { + if (mod.module) { + return mod.module; + } else { + return (mod.module = { + id: mod.map.id, + uri: mod.map.url, + config: function () { + var c, + pkg = getOwn(config.pkgs, mod.map.id); + // For packages, only support config targeted + // at the main module. + c = pkg ? getOwn(config.config, mod.map.id + '/' + pkg.main) : + getOwn(config.config, mod.map.id); + return c || {}; + }, + exports: defined[mod.map.id] + }); + } + } + }; + + function cleanRegistry(id) { + //Clean up machinery used for waiting modules. + delete registry[id]; + delete enabledRegistry[id]; + } + + function breakCycle(mod, traced, processed) { + var id = mod.map.id; + + if (mod.error) { + mod.emit('error', mod.error); + } else { + traced[id] = true; + each(mod.depMaps, function (depMap, i) { + var depId = depMap.id, + dep = getOwn(registry, depId); + + //Only force things that have not completed + //being defined, so still in the registry, + //and only if it has not been matched up + //in the module already. + if (dep && !mod.depMatched[i] && !processed[depId]) { + if (getOwn(traced, depId)) { + mod.defineDep(i, defined[depId]); + mod.check(); //pass false? + } else { + breakCycle(dep, traced, processed); + } + } + }); + processed[id] = true; + } + } + + function checkLoaded() { + var map, modId, err, usingPathFallback, + waitInterval = config.waitSeconds * 1000, + //It is possible to disable the wait interval by using waitSeconds of 0. + expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), + noLoads = [], + reqCalls = [], + stillLoading = false, + needCycleCheck = true; + + //Do not bother if this call was a result of a cycle break. + if (inCheckLoaded) { + return; + } + + inCheckLoaded = true; + + //Figure out the state of all the modules. + eachProp(enabledRegistry, function (mod) { + map = mod.map; + modId = map.id; + + //Skip things that are not enabled or in error state. + if (!mod.enabled) { + return; + } + + if (!map.isDefine) { + reqCalls.push(mod); + } + + if (!mod.error) { + //If the module should be executed, and it has not + //been inited and time is up, remember it. + if (!mod.inited && expired) { + if (hasPathFallback(modId)) { + usingPathFallback = true; + stillLoading = true; + } else { + noLoads.push(modId); + removeScript(modId); + } + } else if (!mod.inited && mod.fetched && map.isDefine) { + stillLoading = true; + if (!map.prefix) { + //No reason to keep looking for unfinished + //loading. If the only stillLoading is a + //plugin resource though, keep going, + //because it may be that a plugin resource + //is waiting on a non-plugin cycle. + return (needCycleCheck = false); + } + } + } + }); + + if (expired && noLoads.length) { + //If wait time expired, throw error of unloaded modules. + err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads); + err.contextName = context.contextName; + return onError(err); + } + + //Not expired, check for a cycle. + if (needCycleCheck) { + each(reqCalls, function (mod) { + breakCycle(mod, {}, {}); + }); + } + + //If still waiting on loads, and the waiting load is something + //other than a plugin resource, or there are still outstanding + //scripts, then just try back later. + if ((!expired || usingPathFallback) && stillLoading) { + //Something is still waiting to load. Wait for it, but only + //if a timeout is not already in effect. + if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { + checkLoadedTimeoutId = setTimeout(function () { + checkLoadedTimeoutId = 0; + checkLoaded(); + }, 50); + } + } + + inCheckLoaded = false; + } + + Module = function (map) { + this.events = getOwn(undefEvents, map.id) || {}; + this.map = map; + this.shim = getOwn(config.shim, map.id); + this.depExports = []; + this.depMaps = []; + this.depMatched = []; + this.pluginMaps = {}; + this.depCount = 0; + + /* this.exports this.factory + this.depMaps = [], + this.enabled, this.fetched + */ + }; + + Module.prototype = { + init: function (depMaps, factory, errback, options) { + options = options || {}; + + //Do not do more inits if already done. Can happen if there + //are multiple define calls for the same module. That is not + //a normal, common case, but it is also not unexpected. + if (this.inited) { + return; + } + + this.factory = factory; + + if (errback) { + //Register for errors on this module. + this.on('error', errback); + } else if (this.events.error) { + //If no errback already, but there are error listeners + //on this module, set up an errback to pass to the deps. + errback = bind(this, function (err) { + this.emit('error', err); + }); + } + + //Do a copy of the dependency array, so that + //source inputs are not modified. For example + //"shim" deps are passed in here directly, and + //doing a direct modification of the depMaps array + //would affect that config. + this.depMaps = depMaps && depMaps.slice(0); + + this.errback = errback; + + //Indicate this module has be initialized + this.inited = true; + + this.ignore = options.ignore; + + //Could have option to init this module in enabled mode, + //or could have been previously marked as enabled. However, + //the dependencies are not known until init is called. So + //if enabled previously, now trigger dependencies as enabled. + if (options.enabled || this.enabled) { + //Enable this module and dependencies. + //Will call this.check() + this.enable(); + } else { + this.check(); + } + }, + + defineDep: function (i, depExports) { + //Because of cycles, defined callback for a given + //export can be called more than once. + if (!this.depMatched[i]) { + this.depMatched[i] = true; + this.depCount -= 1; + this.depExports[i] = depExports; + } + }, + + fetch: function () { + if (this.fetched) { + return; + } + this.fetched = true; + + context.startTime = (new Date()).getTime(); + + var map = this.map; + + //If the manager is for a plugin managed resource, + //ask the plugin to load it now. + if (this.shim) { + context.makeRequire(this.map, { + enableBuildCallback: true + })(this.shim.deps || [], bind(this, function () { + return map.prefix ? this.callPlugin() : this.load(); + })); + } else { + //Regular dependency. + return map.prefix ? this.callPlugin() : this.load(); + } + }, + + load: function () { + var url = this.map.url; + + //Regular dependency. + if (!urlFetched[url]) { + urlFetched[url] = true; + context.load(this.map.id, url); + } + }, + + /** + * Checks if the module is ready to define itself, and if so, + * define it. + */ + check: function () { + if (!this.enabled || this.enabling) { + return; + } + + var err, cjsModule, + id = this.map.id, + depExports = this.depExports, + exports = this.exports, + factory = this.factory; + + if (!this.inited) { + this.fetch(); + } else if (this.error) { + this.emit('error', this.error); + } else if (!this.defining) { + //The factory could trigger another require call + //that would result in checking this module to + //define itself again. If already in the process + //of doing that, skip this work. + this.defining = true; + + if (this.depCount < 1 && !this.defined) { + if (isFunction(factory)) { + //If there is an error listener, favor passing + //to that instead of throwing an error. However, + //only do it for define()'d modules. require + //errbacks should not be called for failures in + //their callbacks (#699). However if a global + //onError is set, use that. + if ((this.events.error && this.map.isDefine) || + req.onError !== defaultOnError) { + try { + exports = context.execCb(id, factory, depExports, exports); + } catch (e) { + err = e; + } + } else { + exports = context.execCb(id, factory, depExports, exports); + } + + if (this.map.isDefine) { + //If setting exports via 'module' is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + cjsModule = this.module; + if (cjsModule && + cjsModule.exports !== undefined && + //Make sure it is not already the exports value + cjsModule.exports !== this.exports) { + exports = cjsModule.exports; + } else if (exports === undefined && this.usingExports) { + //exports already set the defined value. + exports = this.exports; + } + } + + if (err) { + err.requireMap = this.map; + err.requireModules = this.map.isDefine ? [this.map.id] : null; + err.requireType = this.map.isDefine ? 'define' : 'require'; + return onError((this.error = err)); + } + + } else { + //Just a literal value + exports = factory; + } + + this.exports = exports; + + if (this.map.isDefine && !this.ignore) { + defined[id] = exports; + + if (req.onResourceLoad) { + req.onResourceLoad(context, this.map, this.depMaps); + } + } + + //Clean up + cleanRegistry(id); + + this.defined = true; + } + + //Finished the define stage. Allow calling check again + //to allow define notifications below in the case of a + //cycle. + this.defining = false; + + if (this.defined && !this.defineEmitted) { + this.defineEmitted = true; + this.emit('defined', this.exports); + this.defineEmitComplete = true; + } + + } + }, + + callPlugin: function () { + var map = this.map, + id = map.id, + //Map already normalized the prefix. + pluginMap = makeModuleMap(map.prefix); + + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(pluginMap); + + on(pluginMap, 'defined', bind(this, function (plugin) { + var load, normalizedMap, normalizedMod, + name = this.map.name, + parentName = this.map.parentMap ? this.map.parentMap.name : null, + localRequire = context.makeRequire(map.parentMap, { + enableBuildCallback: true + }); + + //If current map is not normalized, wait for that + //normalized name to load instead of continuing. + if (this.map.unnormalized) { + //Normalize the ID if the plugin allows it. + if (plugin.normalize) { + name = plugin.normalize(name, function (name) { + return normalize(name, parentName, true); + }) || ''; + } + + //prefix and name should already be normalized, no need + //for applying map config again either. + normalizedMap = makeModuleMap(map.prefix + '!' + name, + this.map.parentMap); + on(normalizedMap, + 'defined', bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true, + ignore: true + }); + })); + + normalizedMod = getOwn(registry, normalizedMap.id); + if (normalizedMod) { + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(normalizedMap); + + if (this.events.error) { + normalizedMod.on('error', bind(this, function (err) { + this.emit('error', err); + })); + } + normalizedMod.enable(); + } + + return; + } + + load = bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true + }); + }); + + load.error = bind(this, function (err) { + this.inited = true; + this.error = err; + err.requireModules = [id]; + + //Remove temp unnormalized modules for this module, + //since they will never be resolved otherwise now. + eachProp(registry, function (mod) { + if (mod.map.id.indexOf(id + '_unnormalized') === 0) { + cleanRegistry(mod.map.id); + } + }); + + onError(err); + }); + + //Allow plugins to load other code without having to know the + //context or how to 'complete' the load. + load.fromText = bind(this, function (text, textAlt) { + /*jslint evil: true */ + var moduleName = map.name, + moduleMap = makeModuleMap(moduleName), + hasInteractive = useInteractive; + + //As of 2.1.0, support just passing the text, to reinforce + //fromText only being called once per resource. Still + //support old style of passing moduleName but discard + //that moduleName in favor of the internal ref. + if (textAlt) { + text = textAlt; + } + + //Turn off interactive script matching for IE for any define + //calls in the text, then turn it back on at the end. + if (hasInteractive) { + useInteractive = false; + } + + //Prime the system by creating a module instance for + //it. + getModule(moduleMap); + + //Transfer any config to this other module. + if (hasProp(config.config, id)) { + config.config[moduleName] = config.config[id]; + } + + try { + req.exec(text); + } catch (e) { + return onError(makeError('fromtexteval', + 'fromText eval for ' + id + + ' failed: ' + e, + e, + [id])); + } + + if (hasInteractive) { + useInteractive = true; + } + + //Mark this as a dependency for the plugin + //resource + this.depMaps.push(moduleMap); + + //Support anonymous modules. + context.completeLoad(moduleName); + + //Bind the value of that module to the value for this + //resource ID. + localRequire([moduleName], load); + }); + + //Use parentName here since the plugin's name is not reliable, + //could be some weird string with no path that actually wants to + //reference the parentName's path. + plugin.load(map.name, localRequire, load, config); + })); + + context.enable(pluginMap, this); + this.pluginMaps[pluginMap.id] = pluginMap; + }, + + enable: function () { + enabledRegistry[this.map.id] = this; + this.enabled = true; + + //Set flag mentioning that the module is enabling, + //so that immediate calls to the defined callbacks + //for dependencies do not trigger inadvertent load + //with the depCount still being zero. + this.enabling = true; + + //Enable each dependency + each(this.depMaps, bind(this, function (depMap, i) { + var id, mod, handler; + + if (typeof depMap === 'string') { + //Dependency needs to be converted to a depMap + //and wired up to this module. + depMap = makeModuleMap(depMap, + (this.map.isDefine ? this.map : this.map.parentMap), + false, + !this.skipMap); + this.depMaps[i] = depMap; + + handler = getOwn(handlers, depMap.id); + + if (handler) { + this.depExports[i] = handler(this); + return; + } + + this.depCount += 1; + + on(depMap, 'defined', bind(this, function (depExports) { + this.defineDep(i, depExports); + this.check(); + })); + + if (this.errback) { + on(depMap, 'error', bind(this, this.errback)); + } + } + + id = depMap.id; + mod = registry[id]; + + //Skip special modules like 'require', 'exports', 'module' + //Also, don't call enable if it is already enabled, + //important in circular dependency cases. + if (!hasProp(handlers, id) && mod && !mod.enabled) { + context.enable(depMap, this); + } + })); + + //Enable each plugin that is used in + //a dependency + eachProp(this.pluginMaps, bind(this, function (pluginMap) { + var mod = getOwn(registry, pluginMap.id); + if (mod && !mod.enabled) { + context.enable(pluginMap, this); + } + })); + + this.enabling = false; + + this.check(); + }, + + on: function (name, cb) { + var cbs = this.events[name]; + if (!cbs) { + cbs = this.events[name] = []; + } + cbs.push(cb); + }, + + emit: function (name, evt) { + each(this.events[name], function (cb) { + cb(evt); + }); + if (name === 'error') { + //Now that the error handler was triggered, remove + //the listeners, since this broken Module instance + //can stay around for a while in the registry. + delete this.events[name]; + } + } + }; + + function callGetModule(args) { + //Skip modules already defined. + if (!hasProp(defined, args[0])) { + getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); + } + } + + function removeListener(node, func, name, ieName) { + //Favor detachEvent because of IE9 + //issue, see attachEvent/addEventListener comment elsewhere + //in this file. + if (node.detachEvent && !isOpera) { + //Probably IE. If not it will throw an error, which will be + //useful to know. + if (ieName) { + node.detachEvent(ieName, func); + } + } else { + node.removeEventListener(name, func, false); + } + } + + /** + * Given an event from a script node, get the requirejs info from it, + * and then removes the event listeners on the node. + * @param {Event} evt + * @returns {Object} + */ + function getScriptData(evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + var node = evt.currentTarget || evt.srcElement; + + //Remove the listeners once here. + removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange'); + removeListener(node, context.onScriptError, 'error'); + + return { + node: node, + id: node && node.getAttribute('data-requiremodule') + }; + } + + function intakeDefines() { + var args; + + //Any defined modules in the global queue, intake them now. + takeGlobalQueue(); + + //Make sure any remaining defQueue items get properly processed. + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); + } else { + //args are id, deps, factory. Should be normalized by the + //define() function. + callGetModule(args); + } + } + } + + context = { + config: config, + contextName: contextName, + registry: registry, + defined: defined, + urlFetched: urlFetched, + defQueue: defQueue, + Module: Module, + makeModuleMap: makeModuleMap, + nextTick: req.nextTick, + onError: onError, + + /** + * Set a configuration for the context. + * @param {Object} cfg config object to integrate. + */ + configure: function (cfg) { + //Make sure the baseUrl ends in a slash. + if (cfg.baseUrl) { + if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { + cfg.baseUrl += '/'; + } + } + + //Save off the paths and packages since they require special processing, + //they are additive. + var pkgs = config.pkgs, + shim = config.shim, + objs = { + paths: true, + config: true, + map: true + }; + + eachProp(cfg, function (value, prop) { + if (objs[prop]) { + if (prop === 'map') { + if (!config.map) { + config.map = {}; + } + mixin(config[prop], value, true, true); + } else { + mixin(config[prop], value, true); + } + } else { + config[prop] = value; + } + }); + + //Merge shim + if (cfg.shim) { + eachProp(cfg.shim, function (value, id) { + //Normalize the structure + if (isArray(value)) { + value = { + deps: value + }; + } + if ((value.exports || value.init) && !value.exportsFn) { + value.exportsFn = context.makeShimExports(value); + } + shim[id] = value; + }); + config.shim = shim; + } + + //Adjust packages if necessary. + if (cfg.packages) { + each(cfg.packages, function (pkgObj) { + var location; + + pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj; + location = pkgObj.location; + + //Create a brand new object on pkgs, since currentPackages can + //be passed in again, and config.pkgs is the internal transformed + //state for all package configs. + pkgs[pkgObj.name] = { + name: pkgObj.name, + location: location || pkgObj.name, + //Remove leading dot in main, so main paths are normalized, + //and remove any trailing .js, since different package + //envs have different conventions: some use a module name, + //some use a file name. + main: (pkgObj.main || 'main') + .replace(currDirRegExp, '') + .replace(jsSuffixRegExp, '') + }; + }); + + //Done with modifications, assing packages back to context config + config.pkgs = pkgs; + } + + //If there are any "waiting to execute" modules in the registry, + //update the maps for them, since their info, like URLs to load, + //may have changed. + eachProp(registry, function (mod, id) { + //If module already has init called, since it is too + //late to modify them, and ignore unnormalized ones + //since they are transient. + if (!mod.inited && !mod.map.unnormalized) { + mod.map = makeModuleMap(id); + } + }); + + //If a deps array or a config callback is specified, then call + //require with those args. This is useful when require is defined as a + //config object before require.js is loaded. + if (cfg.deps || cfg.callback) { + context.require(cfg.deps || [], cfg.callback); + } + }, + + makeShimExports: function (value) { + function fn() { + var ret; + if (value.init) { + ret = value.init.apply(global, arguments); + } + return ret || (value.exports && getGlobal(value.exports)); + } + return fn; + }, + + makeRequire: function (relMap, options) { + options = options || {}; + + function localRequire(deps, callback, errback) { + var id, map, requireMod; + + if (options.enableBuildCallback && callback && isFunction(callback)) { + callback.__requireJsBuild = true; + } + + if (typeof deps === 'string') { + if (isFunction(callback)) { + //Invalid call + return onError(makeError('requireargs', 'Invalid require call'), errback); + } + + //If require|exports|module are requested, get the + //value for them from the special handlers. Caveat: + //this only works while module is being defined. + if (relMap && hasProp(handlers, deps)) { + return handlers[deps](registry[relMap.id]); + } + + //Synchronous access to one module. If require.get is + //available (as in the Node adapter), prefer that. + if (req.get) { + return req.get(context, deps, relMap, localRequire); + } + + //Normalize module name, if it contains . or .. + map = makeModuleMap(deps, relMap, false, true); + id = map.id; + + if (!hasProp(defined, id)) { + return onError(makeError('notloaded', 'Module name "' + + id + + '" has not been loaded yet for context: ' + + contextName + + (relMap ? '' : '. Use require([])'))); + } + return defined[id]; + } + + //Grab defines waiting in the global queue. + intakeDefines(); + + //Mark all the dependencies as needing to be loaded. + context.nextTick(function () { + //Some defines could have been added since the + //require call, collect them. + intakeDefines(); + + requireMod = getModule(makeModuleMap(null, relMap)); + + //Store if map config should be applied to this require + //call for dependencies. + requireMod.skipMap = options.skipMap; + + requireMod.init(deps, callback, errback, { + enabled: true + }); + + checkLoaded(); + }); + + return localRequire; + } + + mixin(localRequire, { + isBrowser: isBrowser, + + /** + * Converts a module name + .extension into an URL path. + * *Requires* the use of a module name. It does not support using + * plain URLs like nameToUrl. + */ + toUrl: function (moduleNamePlusExt) { + var ext, + index = moduleNamePlusExt.lastIndexOf('.'), + segment = moduleNamePlusExt.split('/')[0], + isRelative = segment === '.' || segment === '..'; + + //Have a file extension alias, and it is not the + //dots from a relative path. + if (index !== -1 && (!isRelative || index > 1)) { + ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); + moduleNamePlusExt = moduleNamePlusExt.substring(0, index); + } + + return context.nameToUrl(normalize(moduleNamePlusExt, + relMap && relMap.id, true), ext, true); + }, + + defined: function (id) { + return hasProp(defined, makeModuleMap(id, relMap, false, true).id); + }, + + specified: function (id) { + id = makeModuleMap(id, relMap, false, true).id; + return hasProp(defined, id) || hasProp(registry, id); + } + }); + + //Only allow undef on top level require calls + if (!relMap) { + localRequire.undef = function (id) { + //Bind any waiting define() calls to this context, + //fix for #408 + takeGlobalQueue(); + + var map = makeModuleMap(id, relMap, true), + mod = getOwn(registry, id); + + removeScript(id); + + delete defined[id]; + delete urlFetched[map.url]; + delete undefEvents[id]; + + if (mod) { + //Hold on to listeners in case the + //module will be attempted to be reloaded + //using a different config. + if (mod.events.defined) { + undefEvents[id] = mod.events; + } + + cleanRegistry(id); + } + }; + } + + return localRequire; + }, + + /** + * Called to enable a module if it is still in the registry + * awaiting enablement. A second arg, parent, the parent module, + * is passed in for context, when this method is overriden by + * the optimizer. Not shown here to keep code compact. + */ + enable: function (depMap) { + var mod = getOwn(registry, depMap.id); + if (mod) { + getModule(depMap).enable(); + } + }, + + /** + * Internal method used by environment adapters to complete a load event. + * A load event could be a script load or just a load pass from a synchronous + * load call. + * @param {String} moduleName the name of the module to potentially complete. + */ + completeLoad: function (moduleName) { + var found, args, mod, + shim = getOwn(config.shim, moduleName) || {}, + shExports = shim.exports; + + takeGlobalQueue(); + + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + args[0] = moduleName; + //If already found an anonymous module and bound it + //to this name, then this is some other anon module + //waiting for its completeLoad to fire. + if (found) { + break; + } + found = true; + } else if (args[0] === moduleName) { + //Found matching define call for this script! + found = true; + } + + callGetModule(args); + } + + //Do this after the cycle of callGetModule in case the result + //of those calls/init calls changes the registry. + mod = getOwn(registry, moduleName); + + if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { + if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { + if (hasPathFallback(moduleName)) { + return; + } else { + return onError(makeError('nodefine', + 'No define call for ' + moduleName, + null, + [moduleName])); + } + } else { + //A script that does not call define(), so just simulate + //the call for it. + callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); + } + } + + checkLoaded(); + }, + + /** + * Converts a module name to a file path. Supports cases where + * moduleName may actually be just an URL. + * Note that it **does not** call normalize on the moduleName, + * it is assumed to have already been normalized. This is an + * internal API, not a public one. Use toUrl for the public API. + */ + nameToUrl: function (moduleName, ext, skipExt) { + var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url, + parentPath; + + //If a colon is in the URL, it indicates a protocol is used and it is just + //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) + //or ends with .js, then assume the user meant to use an url and not a module id. + //The slash is important for protocol-less URLs as well as full paths. + if (req.jsExtRegExp.test(moduleName)) { + //Just a plain path, not module name lookup, so just return it. + //Add extension if it is included. This is a bit wonky, only non-.js things pass + //an extension, this method probably needs to be reworked. + url = moduleName + (ext || ''); + } else { + //A module that needs to be converted to a path. + paths = config.paths; + pkgs = config.pkgs; + + syms = moduleName.split('/'); + //For each module name segment, see if there is a path + //registered for it. Start with most specific name + //and work up from it. + for (i = syms.length; i > 0; i -= 1) { + parentModule = syms.slice(0, i).join('/'); + pkg = getOwn(pkgs, parentModule); + parentPath = getOwn(paths, parentModule); + if (parentPath) { + //If an array, it means there are a few choices, + //Choose the one that is desired + if (isArray(parentPath)) { + parentPath = parentPath[0]; + } + syms.splice(0, i, parentPath); + break; + } else if (pkg) { + //If module name is just the package name, then looking + //for the main module. + if (moduleName === pkg.name) { + pkgPath = pkg.location + '/' + pkg.main; + } else { + pkgPath = pkg.location; + } + syms.splice(0, i, pkgPath); + break; + } + } + + //Join the path parts together, then figure out if baseUrl is needed. + url = syms.join('/'); + url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js')); + url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; + } + + return config.urlArgs ? url + + ((url.indexOf('?') === -1 ? '?' : '&') + + config.urlArgs) : url; + }, + + //Delegates to req.load. Broken out as a separate function to + //allow overriding in the optimizer. + load: function (id, url) { + req.load(context, id, url); + }, + + /** + * Executes a module callback function. Broken out as a separate function + * solely to allow the build system to sequence the files in the built + * layer in the right sequence. + * + * @private + */ + execCb: function (name, callback, args, exports) { + return callback.apply(exports, args); + }, + + /** + * callback for script loads, used to check status of loading. + * + * @param {Event} evt the event from the browser for the script + * that was loaded. + */ + onScriptLoad: function (evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + if (evt.type === 'load' || + (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { + //Reset interactive script so a script node is not held onto for + //to long. + interactiveScript = null; + + //Pull out the name of the module and the context. + var data = getScriptData(evt); + context.completeLoad(data.id); + } + }, + + /** + * Callback for script errors. + */ + onScriptError: function (evt) { + var data = getScriptData(evt); + if (!hasPathFallback(data.id)) { + return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id])); + } + } + }; + + context.require = context.makeRequire(); + return context; + } + + /** + * Main entry point. + * + * If the only argument to require is a string, then the module that + * is represented by that string is fetched for the appropriate context. + * + * If the first argument is an array, then it will be treated as an array + * of dependency string names to fetch. An optional function callback can + * be specified to execute when all of those dependencies are available. + * + * Make a local req variable to help Caja compliance (it assumes things + * on a require that are not standardized), and to give a short + * name for minification/local scope use. + */ + req = requirejs = function (deps, callback, errback, optional) { + + //Find the right context, use default + var context, config, + contextName = defContextName; + + // Determine if have config object in the call. + if (!isArray(deps) && typeof deps !== 'string') { + // deps is a config object + config = deps; + if (isArray(callback)) { + // Adjust args if there are dependencies + deps = callback; + callback = errback; + errback = optional; + } else { + deps = []; + } + } + + if (config && config.context) { + contextName = config.context; + } + + context = getOwn(contexts, contextName); + if (!context) { + context = contexts[contextName] = req.s.newContext(contextName); + } + + if (config) { + context.configure(config); + } + + return context.require(deps, callback, errback); + }; + + /** + * Support require.config() to make it easier to cooperate with other + * AMD loaders on globally agreed names. + */ + req.config = function (config) { + return req(config); + }; + + /** + * Execute something after the current tick + * of the event loop. Override for other envs + * that have a better solution than setTimeout. + * @param {Function} fn function to execute later. + */ + req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) { + setTimeout(fn, 4); + } : function (fn) { fn(); }; + + /** + * Export require as a global, but only if it does not already exist. + */ + if (!require) { + require = req; + } + + req.version = version; + + //Used to filter out dependencies that are already paths. + req.jsExtRegExp = /^\/|:|\?|\.js$/; + req.isBrowser = isBrowser; + s = req.s = { + contexts: contexts, + newContext: newContext + }; + + //Create default context. + req({}); + + //Exports some context-sensitive methods on global require. + each([ + 'toUrl', + 'undef', + 'defined', + 'specified' + ], function (prop) { + //Reference from contexts instead of early binding to default context, + //so that during builds, the latest instance of the default context + //with its config gets used. + req[prop] = function () { + var ctx = contexts[defContextName]; + return ctx.require[prop].apply(ctx, arguments); + }; + }); + + if (isBrowser) { + head = s.head = document.getElementsByTagName('head')[0]; + //If BASE tag is in play, using appendChild is a problem for IE6. + //When that browser dies, this can be removed. Details in this jQuery bug: + //http://dev.jquery.com/ticket/2709 + baseElement = document.getElementsByTagName('base')[0]; + if (baseElement) { + head = s.head = baseElement.parentNode; + } + } + + /** + * Any errors that require explicitly generates will be passed to this + * function. Intercept/override it if you want custom error handling. + * @param {Error} err the error object. + */ + req.onError = defaultOnError; + + /** + * Creates the node for the load command. Only used in browser envs. + */ + req.createNode = function (config, moduleName, url) { + var node = config.xhtml ? + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); + node.type = config.scriptType || 'text/javascript'; + node.charset = 'utf-8'; + node.async = true; + return node; + }; + + /** + * Does the request to load a module for the browser case. + * Make this a separate function to allow other environments + * to override it. + * + * @param {Object} context the require context to find state. + * @param {String} moduleName the name of the module. + * @param {Object} url the URL to the module. + */ + req.load = function (context, moduleName, url) { + var config = (context && context.config) || {}, + node; + if (isBrowser) { + //In the browser so use a script tag + node = req.createNode(config, moduleName, url); + + node.setAttribute('data-requirecontext', context.contextName); + node.setAttribute('data-requiremodule', moduleName); + + //Set up load listener. Test attachEvent first because IE9 has + //a subtle issue in its addEventListener and script onload firings + //that do not match the behavior of all other browsers with + //addEventListener support, which fire the onload event for a + //script right after the script execution. See: + //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution + //UNFORTUNATELY Opera implements attachEvent but does not follow the script + //script execution mode. + if (node.attachEvent && + //Check if node.attachEvent is artificially added by custom script or + //natively supported by browser + //read https://github.com/jrburke/requirejs/issues/187 + //if we can NOT find [native code] then it must NOT natively supported. + //in IE8, node.attachEvent does not have toString() + //Note the test for "[native code" with no closing brace, see: + //https://github.com/jrburke/requirejs/issues/273 + !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && + !isOpera) { + //Probably IE. IE (at least 6-8) do not fire + //script onload right after executing the script, so + //we cannot tie the anonymous define call to a name. + //However, IE reports the script as being in 'interactive' + //readyState at the time of the define call. + useInteractive = true; + + node.attachEvent('onreadystatechange', context.onScriptLoad); + //It would be great to add an error handler here to catch + //404s in IE9+. However, onreadystatechange will fire before + //the error handler, so that does not help. If addEventListener + //is used, then IE will fire error before load, but we cannot + //use that pathway given the connect.microsoft.com issue + //mentioned above about not doing the 'script execute, + //then fire the script load event listener before execute + //next script' that other browsers do. + //Best hope: IE10 fixes the issues, + //and then destroys all installs of IE 6-9. + //node.attachEvent('onerror', context.onScriptError); + } else { + node.addEventListener('load', context.onScriptLoad, false); + node.addEventListener('error', context.onScriptError, false); + } + node.src = url; + + //For some cache cases in IE 6-8, the script executes before the end + //of the appendChild execution, so to tie an anonymous define + //call to the module name (which is stored on the node), hold on + //to a reference to this node, but clear after the DOM insertion. + currentlyAddingScript = node; + if (baseElement) { + head.insertBefore(node, baseElement); + } else { + head.appendChild(node); + } + currentlyAddingScript = null; + + return node; + } else if (isWebWorker) { + try { + //In a web worker, use importScripts. This is not a very + //efficient use of importScripts, importScripts will block until + //its script is downloaded and evaluated. However, if web workers + //are in play, the expectation that a build has been done so that + //only one script needs to be loaded anyway. This may need to be + //reevaluated if other use cases become common. + importScripts(url); + + //Account for anonymous modules + context.completeLoad(moduleName); + } catch (e) { + context.onError(makeError('importscripts', + 'importScripts failed for ' + + moduleName + ' at ' + url, + e, + [moduleName])); + } + } + }; + + function getInteractiveScript() { + if (interactiveScript && interactiveScript.readyState === 'interactive') { + return interactiveScript; + } + + eachReverse(scripts(), function (script) { + if (script.readyState === 'interactive') { + return (interactiveScript = script); + } + }); + return interactiveScript; + } + + //Look for a data-main script attribute, which could also adjust the baseUrl. + if (isBrowser && !cfg.skipDataMain) { + //Figure out baseUrl. Get it from the script tag with require.js in it. + eachReverse(scripts(), function (script) { + //Set the 'head' where we can append children by + //using the script's parent. + if (!head) { + head = script.parentNode; + } + + //Look for a data-main attribute to set main script for the page + //to load. If it is there, the path to data main becomes the + //baseUrl, if it is not already set. + dataMain = script.getAttribute('data-main'); + if (dataMain) { + //Preserve dataMain in case it is a path (i.e. contains '?') + mainScript = dataMain; + + //Set final baseUrl if there is not already an explicit one. + if (!cfg.baseUrl) { + //Pull off the directory of data-main for use as the + //baseUrl. + src = mainScript.split('/'); + mainScript = src.pop(); + subPath = src.length ? src.join('/') + '/' : './'; + + cfg.baseUrl = subPath; + } + + //Strip off any trailing .js since mainScript is now + //like a module name. + mainScript = mainScript.replace(jsSuffixRegExp, ''); + + //If mainScript is still a path, fall back to dataMain + if (req.jsExtRegExp.test(mainScript)) { + mainScript = dataMain; + } + + //Put the data-main script in the files to load. + cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript]; + + return true; + } + }); + } + + /** + * The function that handles definitions of modules. Differs from + * require() in that a string for the module should be the first argument, + * and the function to execute after dependencies are loaded should + * return a value to define the module corresponding to the first argument's + * name. + */ + define = function (name, deps, callback) { + var node, context; + + //Allow for anonymous modules + if (typeof name !== 'string') { + //Adjust args appropriately + callback = deps; + deps = name; + name = null; + } + + //This module may not have dependencies + if (!isArray(deps)) { + callback = deps; + deps = null; + } + + //If no name, and callback is a function, then figure out if it a + //CommonJS thing with dependencies. + if (!deps && isFunction(callback)) { + deps = []; + //Remove comments from the callback string, + //look for require calls, and pull them into the dependencies, + //but only if there are function args. + if (callback.length) { + callback + .toString() + .replace(commentRegExp, '') + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + + //May be a CommonJS thing even without require calls, but still + //could use exports, and module. Avoid doing exports and module + //work though if it just needs require. + //REQUIRES the function to expect the CommonJS variables in the + //order listed below. + deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); + } + } + + //If in IE 6-8 and hit an anonymous define() call, do the interactive + //work. + if (useInteractive) { + node = currentlyAddingScript || getInteractiveScript(); + if (node) { + if (!name) { + name = node.getAttribute('data-requiremodule'); + } + context = contexts[node.getAttribute('data-requirecontext')]; + } + } + + //Always save off evaluating the def call until the script onload handler. + //This allows multiple modules to be in a file without prematurely + //tracing dependencies, and allows for anonymous module support, + //where the module name is not known until the script onload event + //occurs. If no context, use the global queue, and get it processed + //in the onscript load callback. + (context ? context.defQueue : globalDefQueue).push([name, deps, callback]); + }; + + define.amd = { + jQuery: true + }; + + + /** + * Executes the text. Normally just uses eval, but can be modified + * to use a better, environment-specific call. Only used for transpiling + * loader plugins, not for plain JS modules. + * @param {String} text the text to execute/evaluate. + */ + req.exec = function (text) { + /*jslint evil: true */ + return eval(text); + }; + + //Set up with config info. + req(cfg); +}(this)); diff --git a/scripts/e2e-test.bat b/scripts/e2e-test.bat new file mode 100644 index 00000000..0b2aee60 --- /dev/null +++ b/scripts/e2e-test.bat @@ -0,0 +1,11 @@ +@echo off + +REM Windows script for running e2e tests +REM You have to run server and capture some browser first +REM +REM Requirements: +REM - NodeJS (http://nodejs.org/) +REM - Karma (npm install -g karma) + +set BASE_DIR=%~dp0 +karma start "%BASE_DIR%\..\config\karma-e2e.conf.js" %* diff --git a/scripts/e2e-test.sh b/scripts/e2e-test.sh new file mode 100755 index 00000000..47fe8275 --- /dev/null +++ b/scripts/e2e-test.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +BASE_DIR=`dirname $0` + +echo "" +echo "Starting Karma Server (http://karma-runner.github.io)" +echo $BASE_DIR +echo "-------------------------------------------------------------------" + +$BASE_DIR/../node_modules/karma/bin/karma start $BASE_DIR/../config/karma-e2e.conf.js $* diff --git a/scripts/test.bat b/scripts/test.bat new file mode 100644 index 00000000..6571f8f2 --- /dev/null +++ b/scripts/test.bat @@ -0,0 +1,11 @@ +@echo off + +REM Windows script for running unit tests +REM You have to run server and capture some browser first +REM +REM Requirements: +REM - NodeJS (http://nodejs.org/) +REM - Karma (npm install -g karma) + +set BASE_DIR=%~dp0 +karma start "%BASE_DIR%\..\config\karma.conf.js" %* diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 00000000..f6db7624 --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +BASE_DIR=`dirname $0` + +echo "" +echo "Starting Karma Server (http://karma-runner.github.io)" +echo "-------------------------------------------------------------------" + +#$BASE_DIR/../node_modules/karma/bin/karma start $BASE_DIR/../config/karma.conf.js $* +karma start $BASE_DIR/../config/karma.conf.js $* diff --git a/scripts/watchr.rb b/scripts/watchr.rb new file mode 100755 index 00000000..89ef656d --- /dev/null +++ b/scripts/watchr.rb @@ -0,0 +1,19 @@ +#!/usr/bin/env watchr + +# config file for watchr http://github.com/mynyml/watchr +# install: gem install watchr +# run: watch watchr.rb +# note: make sure that you have jstd server running (server.sh) and a browser captured + +log_file = File.expand_path(File.dirname(__FILE__) + '/../logs/jstd.log') + +`cd ..` +`touch #{log_file}` + +puts "String watchr... log file: #{log_file}" + +watch( '(app/js|test/unit)' ) do + `echo "\n\ntest run started @ \`date\`" > #{log_file}` + `scripts/test.sh &> #{log_file}` +end + diff --git a/scripts/web-server.js b/scripts/web-server.js new file mode 100755 index 00000000..3f74441e --- /dev/null +++ b/scripts/web-server.js @@ -0,0 +1,244 @@ +#!/usr/bin/env node + +var util = require('util'), + http = require('http'), + fs = require('fs'), + url = require('url'), + events = require('events'); + +var DEFAULT_PORT = 8000; + +function main(argv) { + new HttpServer({ + 'GET': createServlet(StaticServlet), + 'HEAD': createServlet(StaticServlet) + }).start(Number(argv[2]) || DEFAULT_PORT); +} + +function escapeHtml(value) { + return value.toString(). + replace('<', '<'). + replace('>', '>'). + replace('"', '"'); +} + +function createServlet(Class) { + var servlet = new Class(); + return servlet.handleRequest.bind(servlet); +} + +/** + * An Http server implementation that uses a map of methods to decide + * action routing. + * + * @param {Object} Map of method => Handler function + */ +function HttpServer(handlers) { + this.handlers = handlers; + this.server = http.createServer(this.handleRequest_.bind(this)); +} + +HttpServer.prototype.start = function(port) { + this.port = port; + this.server.listen(port); + util.puts('Http Server running at http://localhost:' + port + '/'); +}; + +HttpServer.prototype.parseUrl_ = function(urlString) { + var parsed = url.parse(urlString); + parsed.pathname = url.resolve('/', parsed.pathname); + return url.parse(url.format(parsed), true); +}; + +HttpServer.prototype.handleRequest_ = function(req, res) { + var logEntry = req.method + ' ' + req.url; + if (req.headers['user-agent']) { + logEntry += ' ' + req.headers['user-agent']; + } + util.puts(logEntry); + req.url = this.parseUrl_(req.url); + var handler = this.handlers[req.method]; + if (!handler) { + res.writeHead(501); + res.end(); + } else { + handler.call(this, req, res); + } +}; + +/** + * Handles static content. + */ +function StaticServlet() {} + +StaticServlet.MimeMap = { + 'txt': 'text/plain', + 'html': 'text/html', + 'css': 'text/css', + 'xml': 'application/xml', + 'json': 'application/json', + 'js': 'application/javascript', + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'gif': 'image/gif', + 'png': 'image/png', +  'svg': 'image/svg+xml' +}; + +StaticServlet.prototype.handleRequest = function(req, res) { + var self = this; + var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){ + return String.fromCharCode(parseInt(hex, 16)); + }); + var parts = path.split('/'); + if (parts[parts.length-1].charAt(0) === '.') + return self.sendForbidden_(req, res, path); + fs.stat(path, function(err, stat) { + if (err) + return self.sendMissing_(req, res, path); + if (stat.isDirectory()) + return self.sendDirectory_(req, res, path); + return self.sendFile_(req, res, path); + }); +} + +StaticServlet.prototype.sendError_ = function(req, res, error) { + res.writeHead(500, { + 'Content-Type': 'text/html' + }); + res.write('\n'); + res.write('Internal Server Error\n'); + res.write('

    Internal Server Error

    '); + res.write('
    ' + escapeHtml(util.inspect(error)) + '
    '); + util.puts('500 Internal Server Error'); + util.puts(util.inspect(error)); +}; + +StaticServlet.prototype.sendMissing_ = function(req, res, path) { + path = path.substring(1); + res.writeHead(404, { + 'Content-Type': 'text/html' + }); + res.write('\n'); + res.write('404 Not Found\n'); + res.write('

    Not Found

    '); + res.write( + '

    The requested URL ' + + escapeHtml(path) + + ' was not found on this server.

    ' + ); + res.end(); + util.puts('404 Not Found: ' + path); +}; + +StaticServlet.prototype.sendForbidden_ = function(req, res, path) { + path = path.substring(1); + res.writeHead(403, { + 'Content-Type': 'text/html' + }); + res.write('\n'); + res.write('403 Forbidden\n'); + res.write('

    Forbidden

    '); + res.write( + '

    You do not have permission to access ' + + escapeHtml(path) + ' on this server.

    ' + ); + res.end(); + util.puts('403 Forbidden: ' + path); +}; + +StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) { + res.writeHead(301, { + 'Content-Type': 'text/html', + 'Location': redirectUrl + }); + res.write('\n'); + res.write('301 Moved Permanently\n'); + res.write('

    Moved Permanently

    '); + res.write( + '

    The document has moved here.

    ' + ); + res.end(); + util.puts('301 Moved Permanently: ' + redirectUrl); +}; + +StaticServlet.prototype.sendFile_ = function(req, res, path) { + var self = this; + var file = fs.createReadStream(path); + res.writeHead(200, { + 'Content-Type': StaticServlet. + MimeMap[path.split('.').pop()] || 'text/plain' + }); + if (req.method === 'HEAD') { + res.end(); + } else { + file.on('data', res.write.bind(res)); + file.on('close', function() { + res.end(); + }); + file.on('error', function(error) { + self.sendError_(req, res, error); + }); + } +}; + +StaticServlet.prototype.sendDirectory_ = function(req, res, path) { + var self = this; + if (path.match(/[^\/]$/)) { + req.url.pathname += '/'; + var redirectUrl = url.format(url.parse(url.format(req.url))); + return self.sendRedirect_(req, res, redirectUrl); + } + fs.readdir(path, function(err, files) { + if (err) + return self.sendError_(req, res, error); + + if (!files.length) + return self.writeDirectoryIndex_(req, res, path, []); + + var remaining = files.length; + files.forEach(function(fileName, index) { + fs.stat(path + '/' + fileName, function(err, stat) { + if (err) + return self.sendError_(req, res, err); + if (stat.isDirectory()) { + files[index] = fileName + '/'; + } + if (!(--remaining)) + return self.writeDirectoryIndex_(req, res, path, files); + }); + }); + }); +}; + +StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) { + path = path.substring(1); + res.writeHead(200, { + 'Content-Type': 'text/html' + }); + if (req.method === 'HEAD') { + res.end(); + return; + } + res.write('\n'); + res.write('' + escapeHtml(path) + '\n'); + res.write('\n'); + res.write('

    Directory: ' + escapeHtml(path) + '

    '); + res.write('
      '); + files.forEach(function(fileName) { + if (fileName.charAt(0) !== '.') { + res.write('
    1. ' + + escapeHtml(fileName) + '
    2. '); + } + }); + res.write('
    '); + res.end(); +}; + +// Must be last, +main(process.argv); diff --git a/test/e2e/runner.html b/test/e2e/runner.html new file mode 100644 index 00000000..859c90e3 --- /dev/null +++ b/test/e2e/runner.html @@ -0,0 +1,11 @@ + + + + End2end Test Runner + + + + + + + diff --git a/test/e2e/scenarios.js b/test/e2e/scenarios.js new file mode 100644 index 00000000..a3a22f02 --- /dev/null +++ b/test/e2e/scenarios.js @@ -0,0 +1,45 @@ +'use strict'; + +/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */ + +describe('my app', function() { + + beforeEach(function() { + browser().navigateTo('app/index.html'); + }); + + + it('should automatically redirect to /view1 when location hash/fragment is empty', function() { + expect(browser().location().url()).toBe("/view1"); + }); + + + describe('view1', function() { + + beforeEach(function() { + browser().navigateTo('#/view1'); + }); + + + it('should render view1 when user navigates to /view1', function() { + expect(element('[ng-view] p:first').text()). + toMatch(/partial for view 1/); + }); + + }); + + + describe('view2', function() { + + beforeEach(function() { + browser().navigateTo('#/view2'); + }); + + + it('should render view2 when user navigates to /view2', function() { + expect(element('[ng-view] p:first').text()). + toMatch(/partial for view 2/); + }); + + }); +}); diff --git a/test/lib/angular/angular-mocks.js b/test/lib/angular/angular-mocks.js new file mode 100644 index 00000000..c85e18a9 --- /dev/null +++ b/test/lib/angular/angular-mocks.js @@ -0,0 +1,2115 @@ +/** + * @license AngularJS v1.2.3 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular, undefined) { + +'use strict'; + +/** + * @ngdoc overview + * @name angular.mock + * @description + * + * Namespace from 'angular-mocks.js' which contains testing related code. + */ +angular.mock = {}; + +/** + * ! This is a private undocumented service ! + * + * @name ngMock.$browser + * + * @description + * This service is a mock implementation of {@link ng.$browser}. It provides fake + * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr, + * cookies, etc... + * + * The api of this service is the same as that of the real {@link ng.$browser $browser}, except + * that there are several helper methods available which can be used in tests. + */ +angular.mock.$BrowserProvider = function() { + this.$get = function() { + return new angular.mock.$Browser(); + }; +}; + +angular.mock.$Browser = function() { + var self = this; + + this.isMock = true; + self.$$url = "http://server/"; + self.$$lastUrl = self.$$url; // used by url polling fn + self.pollFns = []; + + // TODO(vojta): remove this temporary api + self.$$completeOutstandingRequest = angular.noop; + self.$$incOutstandingRequestCount = angular.noop; + + + // register url polling fn + + self.onUrlChange = function(listener) { + self.pollFns.push( + function() { + if (self.$$lastUrl != self.$$url) { + self.$$lastUrl = self.$$url; + listener(self.$$url); + } + } + ); + + return listener; + }; + + self.cookieHash = {}; + self.lastCookieHash = {}; + self.deferredFns = []; + self.deferredNextId = 0; + + self.defer = function(fn, delay) { + delay = delay || 0; + self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId}); + self.deferredFns.sort(function(a,b){ return a.time - b.time;}); + return self.deferredNextId++; + }; + + + /** + * @name ngMock.$browser#defer.now + * @propertyOf ngMock.$browser + * + * @description + * Current milliseconds mock time. + */ + self.defer.now = 0; + + + self.defer.cancel = function(deferId) { + var fnIndex; + + angular.forEach(self.deferredFns, function(fn, index) { + if (fn.id === deferId) fnIndex = index; + }); + + if (fnIndex !== undefined) { + self.deferredFns.splice(fnIndex, 1); + return true; + } + + return false; + }; + + + /** + * @name ngMock.$browser#defer.flush + * @methodOf ngMock.$browser + * + * @description + * Flushes all pending requests and executes the defer callbacks. + * + * @param {number=} number of milliseconds to flush. See {@link #defer.now} + */ + self.defer.flush = function(delay) { + if (angular.isDefined(delay)) { + self.defer.now += delay; + } else { + if (self.deferredFns.length) { + self.defer.now = self.deferredFns[self.deferredFns.length-1].time; + } else { + throw new Error('No deferred tasks to be flushed'); + } + } + + while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) { + self.deferredFns.shift().fn(); + } + }; + + self.$$baseHref = ''; + self.baseHref = function() { + return this.$$baseHref; + }; +}; +angular.mock.$Browser.prototype = { + +/** + * @name ngMock.$browser#poll + * @methodOf ngMock.$browser + * + * @description + * run all fns in pollFns + */ + poll: function poll() { + angular.forEach(this.pollFns, function(pollFn){ + pollFn(); + }); + }, + + addPollFn: function(pollFn) { + this.pollFns.push(pollFn); + return pollFn; + }, + + url: function(url, replace) { + if (url) { + this.$$url = url; + return this; + } + + return this.$$url; + }, + + cookies: function(name, value) { + if (name) { + if (angular.isUndefined(value)) { + delete this.cookieHash[name]; + } else { + if (angular.isString(value) && //strings only + value.length <= 4096) { //strict cookie storage limits + this.cookieHash[name] = value; + } + } + } else { + if (!angular.equals(this.cookieHash, this.lastCookieHash)) { + this.lastCookieHash = angular.copy(this.cookieHash); + this.cookieHash = angular.copy(this.cookieHash); + } + return this.cookieHash; + } + }, + + notifyWhenNoOutstandingRequests: function(fn) { + fn(); + } +}; + + +/** + * @ngdoc object + * @name ngMock.$exceptionHandlerProvider + * + * @description + * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors + * passed into the `$exceptionHandler`. + */ + +/** + * @ngdoc object + * @name ngMock.$exceptionHandler + * + * @description + * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed + * into it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration + * information. + * + * + *
    + *   describe('$exceptionHandlerProvider', function() {
    + *
    + *     it('should capture log messages and exceptions', function() {
    + *
    + *       module(function($exceptionHandlerProvider) {
    + *         $exceptionHandlerProvider.mode('log');
    + *       });
    + *
    + *       inject(function($log, $exceptionHandler, $timeout) {
    + *         $timeout(function() { $log.log(1); });
    + *         $timeout(function() { $log.log(2); throw 'banana peel'; });
    + *         $timeout(function() { $log.log(3); });
    + *         expect($exceptionHandler.errors).toEqual([]);
    + *         expect($log.assertEmpty());
    + *         $timeout.flush();
    + *         expect($exceptionHandler.errors).toEqual(['banana peel']);
    + *         expect($log.log.logs).toEqual([[1], [2], [3]]);
    + *       });
    + *     });
    + *   });
    + * 
    + */ + +angular.mock.$ExceptionHandlerProvider = function() { + var handler; + + /** + * @ngdoc method + * @name ngMock.$exceptionHandlerProvider#mode + * @methodOf ngMock.$exceptionHandlerProvider + * + * @description + * Sets the logging mode. + * + * @param {string} mode Mode of operation, defaults to `rethrow`. + * + * - `rethrow`: If any errors are passed into the handler in tests, it typically + * means that there is a bug in the application or test, so this mock will + * make these tests fail. + * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log` + * mode stores an array of errors in `$exceptionHandler.errors`, to allow later + * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and + * {@link ngMock.$log#reset reset()} + */ + this.mode = function(mode) { + switch(mode) { + case 'rethrow': + handler = function(e) { + throw e; + }; + break; + case 'log': + var errors = []; + + handler = function(e) { + if (arguments.length == 1) { + errors.push(e); + } else { + errors.push([].slice.call(arguments, 0)); + } + }; + + handler.errors = errors; + break; + default: + throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!"); + } + }; + + this.$get = function() { + return handler; + }; + + this.mode('rethrow'); +}; + + +/** + * @ngdoc service + * @name ngMock.$log + * + * @description + * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays + * (one array per logging level). These arrays are exposed as `logs` property of each of the + * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`. + * + */ +angular.mock.$LogProvider = function() { + var debug = true; + + function concat(array1, array2, index) { + return array1.concat(Array.prototype.slice.call(array2, index)); + } + + this.debugEnabled = function(flag) { + if (angular.isDefined(flag)) { + debug = flag; + return this; + } else { + return debug; + } + }; + + this.$get = function () { + var $log = { + log: function() { $log.log.logs.push(concat([], arguments, 0)); }, + warn: function() { $log.warn.logs.push(concat([], arguments, 0)); }, + info: function() { $log.info.logs.push(concat([], arguments, 0)); }, + error: function() { $log.error.logs.push(concat([], arguments, 0)); }, + debug: function() { + if (debug) { + $log.debug.logs.push(concat([], arguments, 0)); + } + } + }; + + /** + * @ngdoc method + * @name ngMock.$log#reset + * @methodOf ngMock.$log + * + * @description + * Reset all of the logging arrays to empty. + */ + $log.reset = function () { + /** + * @ngdoc property + * @name ngMock.$log#log.logs + * @propertyOf ngMock.$log + * + * @description + * Array of messages logged using {@link ngMock.$log#log}. + * + * @example + *
    +       * $log.log('Some Log');
    +       * var first = $log.log.logs.unshift();
    +       * 
    + */ + $log.log.logs = []; + /** + * @ngdoc property + * @name ngMock.$log#info.logs + * @propertyOf ngMock.$log + * + * @description + * Array of messages logged using {@link ngMock.$log#info}. + * + * @example + *
    +       * $log.info('Some Info');
    +       * var first = $log.info.logs.unshift();
    +       * 
    + */ + $log.info.logs = []; + /** + * @ngdoc property + * @name ngMock.$log#warn.logs + * @propertyOf ngMock.$log + * + * @description + * Array of messages logged using {@link ngMock.$log#warn}. + * + * @example + *
    +       * $log.warn('Some Warning');
    +       * var first = $log.warn.logs.unshift();
    +       * 
    + */ + $log.warn.logs = []; + /** + * @ngdoc property + * @name ngMock.$log#error.logs + * @propertyOf ngMock.$log + * + * @description + * Array of messages logged using {@link ngMock.$log#error}. + * + * @example + *
    +       * $log.log('Some Error');
    +       * var first = $log.error.logs.unshift();
    +       * 
    + */ + $log.error.logs = []; + /** + * @ngdoc property + * @name ngMock.$log#debug.logs + * @propertyOf ngMock.$log + * + * @description + * Array of messages logged using {@link ngMock.$log#debug}. + * + * @example + *
    +       * $log.debug('Some Error');
    +       * var first = $log.debug.logs.unshift();
    +       * 
    + */ + $log.debug.logs = []; + }; + + /** + * @ngdoc method + * @name ngMock.$log#assertEmpty + * @methodOf ngMock.$log + * + * @description + * Assert that the all of the logging methods have no logged messages. If messages present, an + * exception is thrown. + */ + $log.assertEmpty = function() { + var errors = []; + angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) { + angular.forEach($log[logLevel].logs, function(log) { + angular.forEach(log, function (logItem) { + errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + + (logItem.stack || '')); + }); + }); + }); + if (errors.length) { + errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or "+ + "an expected log message was not checked and removed:"); + errors.push(''); + throw new Error(errors.join('\n---------\n')); + } + }; + + $log.reset(); + return $log; + }; +}; + + +/** + * @ngdoc service + * @name ngMock.$interval + * + * @description + * Mock implementation of the $interval service. + * + * Use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to + * move forward by `millis` milliseconds and trigger any functions scheduled to run in that + * time. + * + * @param {function()} fn A function that should be called repeatedly. + * @param {number} delay Number of milliseconds between each function call. + * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat + * indefinitely. + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise + * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block. + * @returns {promise} A promise which will be notified on each iteration. + */ +angular.mock.$IntervalProvider = function() { + this.$get = ['$rootScope', '$q', + function($rootScope, $q) { + var repeatFns = [], + nextRepeatId = 0, + now = 0; + + var $interval = function(fn, delay, count, invokeApply) { + var deferred = $q.defer(), + promise = deferred.promise, + iteration = 0, + skipApply = (angular.isDefined(invokeApply) && !invokeApply); + + count = (angular.isDefined(count)) ? count : 0, + promise.then(null, null, fn); + + promise.$$intervalId = nextRepeatId; + + function tick() { + deferred.notify(iteration++); + + if (count > 0 && iteration >= count) { + var fnIndex; + deferred.resolve(iteration); + + angular.forEach(repeatFns, function(fn, index) { + if (fn.id === promise.$$intervalId) fnIndex = index; + }); + + if (fnIndex !== undefined) { + repeatFns.splice(fnIndex, 1); + } + } + + if (!skipApply) $rootScope.$apply(); + } + + repeatFns.push({ + nextTime:(now + delay), + delay: delay, + fn: tick, + id: nextRepeatId, + deferred: deferred + }); + repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;}); + + nextRepeatId++; + return promise; + }; + + $interval.cancel = function(promise) { + var fnIndex; + + angular.forEach(repeatFns, function(fn, index) { + if (fn.id === promise.$$intervalId) fnIndex = index; + }); + + if (fnIndex !== undefined) { + repeatFns[fnIndex].deferred.reject('canceled'); + repeatFns.splice(fnIndex, 1); + return true; + } + + return false; + }; + + /** + * @ngdoc method + * @name ngMock.$interval#flush + * @methodOf ngMock.$interval + * @description + * + * Runs interval tasks scheduled to be run in the next `millis` milliseconds. + * + * @param {number=} millis maximum timeout amount to flush up until. + * + * @return {number} The amount of time moved forward. + */ + $interval.flush = function(millis) { + now += millis; + while (repeatFns.length && repeatFns[0].nextTime <= now) { + var task = repeatFns[0]; + task.fn(); + task.nextTime += task.delay; + repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;}); + } + return millis; + }; + + return $interval; + }]; +}; + + +/* jshint -W101 */ +/* The R_ISO8061_STR regex is never going to fit into the 100 char limit! + * This directive should go inside the anonymous function but a bug in JSHint means that it would + * not be enacted early enough to prevent the warning. + */ +var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/; + +function jsonStringToDate(string) { + var match; + if (match = string.match(R_ISO8061_STR)) { + var date = new Date(0), + tzHour = 0, + tzMin = 0; + if (match[9]) { + tzHour = int(match[9] + match[10]); + tzMin = int(match[9] + match[11]); + } + date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3])); + date.setUTCHours(int(match[4]||0) - tzHour, + int(match[5]||0) - tzMin, + int(match[6]||0), + int(match[7]||0)); + return date; + } + return string; +} + +function int(str) { + return parseInt(str, 10); +} + +function padNumber(num, digits, trim) { + var neg = ''; + if (num < 0) { + neg = '-'; + num = -num; + } + num = '' + num; + while(num.length < digits) num = '0' + num; + if (trim) + num = num.substr(num.length - digits); + return neg + num; +} + + +/** + * @ngdoc object + * @name angular.mock.TzDate + * @description + * + * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`. + * + * Mock of the Date type which has its timezone specified via constructor arg. + * + * The main purpose is to create Date-like instances with timezone fixed to the specified timezone + * offset, so that we can test code that depends on local timezone settings without dependency on + * the time zone settings of the machine where the code is running. + * + * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored) + * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC* + * + * @example + * !!!! WARNING !!!!! + * This is not a complete Date object so only methods that were implemented can be called safely. + * To make matters worse, TzDate instances inherit stuff from Date via a prototype. + * + * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is + * incomplete we might be missing some non-standard methods. This can result in errors like: + * "Date.prototype.foo called on incompatible Object". + * + *
    + * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
    + * newYearInBratislava.getTimezoneOffset() => -60;
    + * newYearInBratislava.getFullYear() => 2010;
    + * newYearInBratislava.getMonth() => 0;
    + * newYearInBratislava.getDate() => 1;
    + * newYearInBratislava.getHours() => 0;
    + * newYearInBratislava.getMinutes() => 0;
    + * newYearInBratislava.getSeconds() => 0;
    + * 
    + * + */ +angular.mock.TzDate = function (offset, timestamp) { + var self = new Date(0); + if (angular.isString(timestamp)) { + var tsStr = timestamp; + + self.origDate = jsonStringToDate(timestamp); + + timestamp = self.origDate.getTime(); + if (isNaN(timestamp)) + throw { + name: "Illegal Argument", + message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string" + }; + } else { + self.origDate = new Date(timestamp); + } + + var localOffset = new Date(timestamp).getTimezoneOffset(); + self.offsetDiff = localOffset*60*1000 - offset*1000*60*60; + self.date = new Date(timestamp + self.offsetDiff); + + self.getTime = function() { + return self.date.getTime() - self.offsetDiff; + }; + + self.toLocaleDateString = function() { + return self.date.toLocaleDateString(); + }; + + self.getFullYear = function() { + return self.date.getFullYear(); + }; + + self.getMonth = function() { + return self.date.getMonth(); + }; + + self.getDate = function() { + return self.date.getDate(); + }; + + self.getHours = function() { + return self.date.getHours(); + }; + + self.getMinutes = function() { + return self.date.getMinutes(); + }; + + self.getSeconds = function() { + return self.date.getSeconds(); + }; + + self.getMilliseconds = function() { + return self.date.getMilliseconds(); + }; + + self.getTimezoneOffset = function() { + return offset * 60; + }; + + self.getUTCFullYear = function() { + return self.origDate.getUTCFullYear(); + }; + + self.getUTCMonth = function() { + return self.origDate.getUTCMonth(); + }; + + self.getUTCDate = function() { + return self.origDate.getUTCDate(); + }; + + self.getUTCHours = function() { + return self.origDate.getUTCHours(); + }; + + self.getUTCMinutes = function() { + return self.origDate.getUTCMinutes(); + }; + + self.getUTCSeconds = function() { + return self.origDate.getUTCSeconds(); + }; + + self.getUTCMilliseconds = function() { + return self.origDate.getUTCMilliseconds(); + }; + + self.getDay = function() { + return self.date.getDay(); + }; + + // provide this method only on browsers that already have it + if (self.toISOString) { + self.toISOString = function() { + return padNumber(self.origDate.getUTCFullYear(), 4) + '-' + + padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' + + padNumber(self.origDate.getUTCDate(), 2) + 'T' + + padNumber(self.origDate.getUTCHours(), 2) + ':' + + padNumber(self.origDate.getUTCMinutes(), 2) + ':' + + padNumber(self.origDate.getUTCSeconds(), 2) + '.' + + padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z'; + }; + } + + //hide all methods not implemented in this mock that the Date prototype exposes + var unimplementedMethods = ['getUTCDay', + 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds', + 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear', + 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', + 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString', + 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf']; + + angular.forEach(unimplementedMethods, function(methodName) { + self[methodName] = function() { + throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock"); + }; + }); + + return self; +}; + +//make "tzDateInstance instanceof Date" return true +angular.mock.TzDate.prototype = Date.prototype; +/* jshint +W101 */ + +angular.mock.animate = angular.module('mock.animate', ['ng']) + + .config(['$provide', function($provide) { + + $provide.decorator('$animate', function($delegate) { + var animate = { + queue : [], + enabled : $delegate.enabled, + flushNext : function(name) { + var tick = animate.queue.shift(); + + if (!tick) throw new Error('No animation to be flushed'); + if(tick.method !== name) { + throw new Error('The next animation is not "' + name + + '", but is "' + tick.method + '"'); + } + tick.fn(); + return tick; + } + }; + + angular.forEach(['enter','leave','move','addClass','removeClass'], function(method) { + animate[method] = function() { + var params = arguments; + animate.queue.push({ + method : method, + params : params, + element : angular.isElement(params[0]) && params[0], + parent : angular.isElement(params[1]) && params[1], + after : angular.isElement(params[2]) && params[2], + fn : function() { + $delegate[method].apply($delegate, params); + } + }); + }; + }); + + return animate; + }); + + }]); + + +/** + * @ngdoc function + * @name angular.mock.dump + * @description + * + * *NOTE*: this is not an injectable instance, just a globally available function. + * + * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for + * debugging. + * + * This method is also available on window, where it can be used to display objects on debug + * console. + * + * @param {*} object - any object to turn into string. + * @return {string} a serialized string of the argument + */ +angular.mock.dump = function(object) { + return serialize(object); + + function serialize(object) { + var out; + + if (angular.isElement(object)) { + object = angular.element(object); + out = angular.element('
    '); + angular.forEach(object, function(element) { + out.append(angular.element(element).clone()); + }); + out = out.html(); + } else if (angular.isArray(object)) { + out = []; + angular.forEach(object, function(o) { + out.push(serialize(o)); + }); + out = '[ ' + out.join(', ') + ' ]'; + } else if (angular.isObject(object)) { + if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) { + out = serializeScope(object); + } else if (object instanceof Error) { + out = object.stack || ('' + object.name + ': ' + object.message); + } else { + // TODO(i): this prevents methods being logged, + // we should have a better way to serialize objects + out = angular.toJson(object, true); + } + } else { + out = String(object); + } + + return out; + } + + function serializeScope(scope, offset) { + offset = offset || ' '; + var log = [offset + 'Scope(' + scope.$id + '): {']; + for ( var key in scope ) { + if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) { + log.push(' ' + key + ': ' + angular.toJson(scope[key])); + } + } + var child = scope.$$childHead; + while(child) { + log.push(serializeScope(child, offset + ' ')); + child = child.$$nextSibling; + } + log.push('}'); + return log.join('\n' + offset); + } +}; + +/** + * @ngdoc object + * @name ngMock.$httpBackend + * @description + * Fake HTTP backend implementation suitable for unit testing applications that use the + * {@link ng.$http $http service}. + * + * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less + * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}. + * + * During unit testing, we want our unit tests to run quickly and have no external dependencies so + * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or + * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is + * to verify whether a certain request has been sent or not, or alternatively just let the + * application make requests, respond with pre-trained responses and assert that the end result is + * what we expect it to be. + * + * This mock implementation can be used to respond with static or dynamic responses via the + * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc). + * + * When an Angular application needs some data from a server, it calls the $http service, which + * sends the request to a real server using $httpBackend service. With dependency injection, it is + * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify + * the requests and respond with some testing data without sending a request to real server. + * + * There are two ways to specify what test data should be returned as http responses by the mock + * backend when the code under test makes http requests: + * + * - `$httpBackend.expect` - specifies a request expectation + * - `$httpBackend.when` - specifies a backend definition + * + * + * # Request Expectations vs Backend Definitions + * + * Request expectations provide a way to make assertions about requests made by the application and + * to define responses for those requests. The test will fail if the expected requests are not made + * or they are made in the wrong order. + * + * Backend definitions allow you to define a fake backend for your application which doesn't assert + * if a particular request was made or not, it just returns a trained response if a request is made. + * The test will pass whether or not the request gets made during testing. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Request expectationsBackend definitions
    Syntax.expect(...).respond(...).when(...).respond(...)
    Typical usagestrict unit testsloose (black-box) unit testing
    Fulfills multiple requestsNOYES
    Order of requests mattersYESNO
    Request requiredYESNO
    Response requiredoptional (see below)YES
    + * + * In cases where both backend definitions and request expectations are specified during unit + * testing, the request expectations are evaluated first. + * + * If a request expectation has no response specified, the algorithm will search your backend + * definitions for an appropriate response. + * + * If a request didn't match any expectation or if the expectation doesn't have the response + * defined, the backend definitions are evaluated in sequential order to see if any of them match + * the request. The response from the first matched definition is returned. + * + * + * # Flushing HTTP requests + * + * The $httpBackend used in production, always responds to requests with responses asynchronously. + * If we preserved this behavior in unit testing, we'd have to create async unit tests, which are + * hard to write, follow and maintain. At the same time the testing mock, can't respond + * synchronously because that would change the execution of the code under test. For this reason the + * mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending + * requests and thus preserving the async api of the backend, while allowing the test to execute + * synchronously. + * + * + * # Unit testing with mock $httpBackend + * The following code shows how to setup and use the mock backend in unit testing a controller. + * First we create the controller under test + * +
    +  // The controller code
    +  function MyController($scope, $http) {
    +    var authToken;
    +
    +    $http.get('/auth.py').success(function(data, status, headers) {
    +      authToken = headers('A-Token');
    +      $scope.user = data;
    +    });
    +
    +    $scope.saveMessage = function(message) {
    +      var headers = { 'Authorization': authToken };
    +      $scope.status = 'Saving...';
    +
    +      $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) {
    +        $scope.status = '';
    +      }).error(function() {
    +        $scope.status = 'ERROR!';
    +      });
    +    };
    +  }
    +  
    + * + * Now we setup the mock backend and create the test specs. + * +
    +    // testing controller
    +    describe('MyController', function() {
    +       var $httpBackend, $rootScope, createController;
    +
    +       beforeEach(inject(function($injector) {
    +         // Set up the mock http service responses
    +         $httpBackend = $injector.get('$httpBackend');
    +         // backend definition common for all tests
    +         $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
    +
    +         // Get hold of a scope (i.e. the root scope)
    +         $rootScope = $injector.get('$rootScope');
    +         // The $controller service is used to create instances of controllers
    +         var $controller = $injector.get('$controller');
    +
    +         createController = function() {
    +           return $controller('MyController', {'$scope' : $rootScope });
    +         };
    +       }));
    +
    +
    +       afterEach(function() {
    +         $httpBackend.verifyNoOutstandingExpectation();
    +         $httpBackend.verifyNoOutstandingRequest();
    +       });
    +
    +
    +       it('should fetch authentication token', function() {
    +         $httpBackend.expectGET('/auth.py');
    +         var controller = createController();
    +         $httpBackend.flush();
    +       });
    +
    +
    +       it('should send msg to server', function() {
    +         var controller = createController();
    +         $httpBackend.flush();
    +
    +         // now you don’t care about the authentication, but
    +         // the controller will still send the request and
    +         // $httpBackend will respond without you having to
    +         // specify the expectation and response for this request
    +
    +         $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
    +         $rootScope.saveMessage('message content');
    +         expect($rootScope.status).toBe('Saving...');
    +         $httpBackend.flush();
    +         expect($rootScope.status).toBe('');
    +       });
    +
    +
    +       it('should send auth header', function() {
    +         var controller = createController();
    +         $httpBackend.flush();
    +
    +         $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
    +           // check if the header was send, if it wasn't the expectation won't
    +           // match the request and the test will fail
    +           return headers['Authorization'] == 'xxx';
    +         }).respond(201, '');
    +
    +         $rootScope.saveMessage('whatever');
    +         $httpBackend.flush();
    +       });
    +    });
    +   
    + */ +angular.mock.$HttpBackendProvider = function() { + this.$get = ['$rootScope', createHttpBackendMock]; +}; + +/** + * General factory function for $httpBackend mock. + * Returns instance for unit testing (when no arguments specified): + * - passing through is disabled + * - auto flushing is disabled + * + * Returns instance for e2e testing (when `$delegate` and `$browser` specified): + * - passing through (delegating request to real backend) is enabled + * - auto flushing is enabled + * + * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified) + * @param {Object=} $browser Auto-flushing enabled if specified + * @return {Object} Instance of $httpBackend mock + */ +function createHttpBackendMock($rootScope, $delegate, $browser) { + var definitions = [], + expectations = [], + responses = [], + responsesPush = angular.bind(responses, responses.push); + + function createResponse(status, data, headers) { + if (angular.isFunction(status)) return status; + + return function() { + return angular.isNumber(status) + ? [status, data, headers] + : [200, status, data]; + }; + } + + // TODO(vojta): change params to: method, url, data, headers, callback + function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) { + var xhr = new MockXhr(), + expectation = expectations[0], + wasExpected = false; + + function prettyPrint(data) { + return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp) + ? data + : angular.toJson(data); + } + + function wrapResponse(wrapped) { + if (!$browser && timeout && timeout.then) timeout.then(handleTimeout); + + return handleResponse; + + function handleResponse() { + var response = wrapped.response(method, url, data, headers); + xhr.$$respHeaders = response[2]; + callback(response[0], response[1], xhr.getAllResponseHeaders()); + } + + function handleTimeout() { + for (var i = 0, ii = responses.length; i < ii; i++) { + if (responses[i] === handleResponse) { + responses.splice(i, 1); + callback(-1, undefined, ''); + break; + } + } + } + } + + if (expectation && expectation.match(method, url)) { + if (!expectation.matchData(data)) + throw new Error('Expected ' + expectation + ' with different data\n' + + 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data); + + if (!expectation.matchHeaders(headers)) + throw new Error('Expected ' + expectation + ' with different headers\n' + + 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' + + prettyPrint(headers)); + + expectations.shift(); + + if (expectation.response) { + responses.push(wrapResponse(expectation)); + return; + } + wasExpected = true; + } + + var i = -1, definition; + while ((definition = definitions[++i])) { + if (definition.match(method, url, data, headers || {})) { + if (definition.response) { + // if $browser specified, we do auto flush all requests + ($browser ? $browser.defer : responsesPush)(wrapResponse(definition)); + } else if (definition.passThrough) { + $delegate(method, url, data, callback, headers, timeout, withCredentials); + } else throw new Error('No response defined !'); + return; + } + } + throw wasExpected ? + new Error('No response defined !') : + new Error('Unexpected request: ' + method + ' ' + url + '\n' + + (expectation ? 'Expected ' + expectation : 'No more request expected')); + } + + /** + * @ngdoc method + * @name ngMock.$httpBackend#when + * @methodOf ngMock.$httpBackend + * @description + * Creates a new backend definition. + * + * @param {string} method HTTP method. + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives + * data string and returns true if the data is as expected. + * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header + * object and returns true if the headers match the current definition. + * @returns {requestHandler} Returns an object with `respond` method that controls how a matched + * request is handled. + * + * - respond – + * `{function([status,] data[, headers])|function(function(method, url, data, headers)}` + * – The respond method takes a set of static data to be returned or a function that can return + * an array containing response status (number), response data (string) and response headers + * (Object). + */ + $httpBackend.when = function(method, url, data, headers) { + var definition = new MockHttpExpectation(method, url, data, headers), + chain = { + respond: function(status, data, headers) { + definition.response = createResponse(status, data, headers); + } + }; + + if ($browser) { + chain.passThrough = function() { + definition.passThrough = true; + }; + } + + definitions.push(definition); + return chain; + }; + + /** + * @ngdoc method + * @name ngMock.$httpBackend#whenGET + * @methodOf ngMock.$httpBackend + * @description + * Creates a new backend definition for GET requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#whenHEAD + * @methodOf ngMock.$httpBackend + * @description + * Creates a new backend definition for HEAD requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#whenDELETE + * @methodOf ngMock.$httpBackend + * @description + * Creates a new backend definition for DELETE requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#whenPOST + * @methodOf ngMock.$httpBackend + * @description + * Creates a new backend definition for POST requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives + * data string and returns true if the data is as expected. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#whenPUT + * @methodOf ngMock.$httpBackend + * @description + * Creates a new backend definition for PUT requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives + * data string and returns true if the data is as expected. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#whenJSONP + * @methodOf ngMock.$httpBackend + * @description + * Creates a new backend definition for JSONP requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + createShortMethods('when'); + + + /** + * @ngdoc method + * @name ngMock.$httpBackend#expect + * @methodOf ngMock.$httpBackend + * @description + * Creates a new request expectation. + * + * @param {string} method HTTP method. + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that + * receives data string and returns true if the data is as expected, or Object if request body + * is in JSON format. + * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header + * object and returns true if the headers match the current expectation. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + * + * - respond – + * `{function([status,] data[, headers])|function(function(method, url, data, headers)}` + * – The respond method takes a set of static data to be returned or a function that can return + * an array containing response status (number), response data (string) and response headers + * (Object). + */ + $httpBackend.expect = function(method, url, data, headers) { + var expectation = new MockHttpExpectation(method, url, data, headers); + expectations.push(expectation); + return { + respond: function(status, data, headers) { + expectation.response = createResponse(status, data, headers); + } + }; + }; + + + /** + * @ngdoc method + * @name ngMock.$httpBackend#expectGET + * @methodOf ngMock.$httpBackend + * @description + * Creates a new request expectation for GET requests. For more info see `expect()`. + * + * @param {string|RegExp} url HTTP url. + * @param {Object=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. See #expect for more info. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#expectHEAD + * @methodOf ngMock.$httpBackend + * @description + * Creates a new request expectation for HEAD requests. For more info see `expect()`. + * + * @param {string|RegExp} url HTTP url. + * @param {Object=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#expectDELETE + * @methodOf ngMock.$httpBackend + * @description + * Creates a new request expectation for DELETE requests. For more info see `expect()`. + * + * @param {string|RegExp} url HTTP url. + * @param {Object=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#expectPOST + * @methodOf ngMock.$httpBackend + * @description + * Creates a new request expectation for POST requests. For more info see `expect()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that + * receives data string and returns true if the data is as expected, or Object if request body + * is in JSON format. + * @param {Object=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#expectPUT + * @methodOf ngMock.$httpBackend + * @description + * Creates a new request expectation for PUT requests. For more info see `expect()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that + * receives data string and returns true if the data is as expected, or Object if request body + * is in JSON format. + * @param {Object=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#expectPATCH + * @methodOf ngMock.$httpBackend + * @description + * Creates a new request expectation for PATCH requests. For more info see `expect()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that + * receives data string and returns true if the data is as expected, or Object if request body + * is in JSON format. + * @param {Object=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + + /** + * @ngdoc method + * @name ngMock.$httpBackend#expectJSONP + * @methodOf ngMock.$httpBackend + * @description + * Creates a new request expectation for JSONP requests. For more info see `expect()`. + * + * @param {string|RegExp} url HTTP url. + * @returns {requestHandler} Returns an object with `respond` method that control how a matched + * request is handled. + */ + createShortMethods('expect'); + + + /** + * @ngdoc method + * @name ngMock.$httpBackend#flush + * @methodOf ngMock.$httpBackend + * @description + * Flushes all pending requests using the trained responses. + * + * @param {number=} count Number of responses to flush (in the order they arrived). If undefined, + * all pending requests will be flushed. If there are no pending requests when the flush method + * is called an exception is thrown (as this typically a sign of programming error). + */ + $httpBackend.flush = function(count) { + $rootScope.$digest(); + if (!responses.length) throw new Error('No pending request to flush !'); + + if (angular.isDefined(count)) { + while (count--) { + if (!responses.length) throw new Error('No more pending request to flush !'); + responses.shift()(); + } + } else { + while (responses.length) { + responses.shift()(); + } + } + $httpBackend.verifyNoOutstandingExpectation(); + }; + + + /** + * @ngdoc method + * @name ngMock.$httpBackend#verifyNoOutstandingExpectation + * @methodOf ngMock.$httpBackend + * @description + * Verifies that all of the requests defined via the `expect` api were made. If any of the + * requests were not made, verifyNoOutstandingExpectation throws an exception. + * + * Typically, you would call this method following each test case that asserts requests using an + * "afterEach" clause. + * + *
    +   *   afterEach($httpBackend.verifyNoOutstandingExpectation);
    +   * 
    + */ + $httpBackend.verifyNoOutstandingExpectation = function() { + $rootScope.$digest(); + if (expectations.length) { + throw new Error('Unsatisfied requests: ' + expectations.join(', ')); + } + }; + + + /** + * @ngdoc method + * @name ngMock.$httpBackend#verifyNoOutstandingRequest + * @methodOf ngMock.$httpBackend + * @description + * Verifies that there are no outstanding requests that need to be flushed. + * + * Typically, you would call this method following each test case that asserts requests using an + * "afterEach" clause. + * + *
    +   *   afterEach($httpBackend.verifyNoOutstandingRequest);
    +   * 
    + */ + $httpBackend.verifyNoOutstandingRequest = function() { + if (responses.length) { + throw new Error('Unflushed requests: ' + responses.length); + } + }; + + + /** + * @ngdoc method + * @name ngMock.$httpBackend#resetExpectations + * @methodOf ngMock.$httpBackend + * @description + * Resets all request expectations, but preserves all backend definitions. Typically, you would + * call resetExpectations during a multiple-phase test when you want to reuse the same instance of + * $httpBackend mock. + */ + $httpBackend.resetExpectations = function() { + expectations.length = 0; + responses.length = 0; + }; + + return $httpBackend; + + + function createShortMethods(prefix) { + angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) { + $httpBackend[prefix + method] = function(url, headers) { + return $httpBackend[prefix](method, url, undefined, headers); + }; + }); + + angular.forEach(['PUT', 'POST', 'PATCH'], function(method) { + $httpBackend[prefix + method] = function(url, data, headers) { + return $httpBackend[prefix](method, url, data, headers); + }; + }); + } +} + +function MockHttpExpectation(method, url, data, headers) { + + this.data = data; + this.headers = headers; + + this.match = function(m, u, d, h) { + if (method != m) return false; + if (!this.matchUrl(u)) return false; + if (angular.isDefined(d) && !this.matchData(d)) return false; + if (angular.isDefined(h) && !this.matchHeaders(h)) return false; + return true; + }; + + this.matchUrl = function(u) { + if (!url) return true; + if (angular.isFunction(url.test)) return url.test(u); + return url == u; + }; + + this.matchHeaders = function(h) { + if (angular.isUndefined(headers)) return true; + if (angular.isFunction(headers)) return headers(h); + return angular.equals(headers, h); + }; + + this.matchData = function(d) { + if (angular.isUndefined(data)) return true; + if (data && angular.isFunction(data.test)) return data.test(d); + if (data && angular.isFunction(data)) return data(d); + if (data && !angular.isString(data)) return angular.equals(data, angular.fromJson(d)); + return data == d; + }; + + this.toString = function() { + return method + ' ' + url; + }; +} + +function MockXhr() { + + // hack for testing $http, $httpBackend + MockXhr.$$lastInstance = this; + + this.open = function(method, url, async) { + this.$$method = method; + this.$$url = url; + this.$$async = async; + this.$$reqHeaders = {}; + this.$$respHeaders = {}; + }; + + this.send = function(data) { + this.$$data = data; + }; + + this.setRequestHeader = function(key, value) { + this.$$reqHeaders[key] = value; + }; + + this.getResponseHeader = function(name) { + // the lookup must be case insensitive, + // that's why we try two quick lookups first and full scan last + var header = this.$$respHeaders[name]; + if (header) return header; + + name = angular.lowercase(name); + header = this.$$respHeaders[name]; + if (header) return header; + + header = undefined; + angular.forEach(this.$$respHeaders, function(headerVal, headerName) { + if (!header && angular.lowercase(headerName) == name) header = headerVal; + }); + return header; + }; + + this.getAllResponseHeaders = function() { + var lines = []; + + angular.forEach(this.$$respHeaders, function(value, key) { + lines.push(key + ': ' + value); + }); + return lines.join('\n'); + }; + + this.abort = angular.noop; +} + + +/** + * @ngdoc function + * @name ngMock.$timeout + * @description + * + * This service is just a simple decorator for {@link ng.$timeout $timeout} service + * that adds a "flush" and "verifyNoPendingTasks" methods. + */ + +angular.mock.$TimeoutDecorator = function($delegate, $browser) { + + /** + * @ngdoc method + * @name ngMock.$timeout#flush + * @methodOf ngMock.$timeout + * @description + * + * Flushes the queue of pending tasks. + * + * @param {number=} delay maximum timeout amount to flush up until + */ + $delegate.flush = function(delay) { + $browser.defer.flush(delay); + }; + + /** + * @ngdoc method + * @name ngMock.$timeout#verifyNoPendingTasks + * @methodOf ngMock.$timeout + * @description + * + * Verifies that there are no pending tasks that need to be flushed. + */ + $delegate.verifyNoPendingTasks = function() { + if ($browser.deferredFns.length) { + throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' + + formatPendingTasksAsString($browser.deferredFns)); + } + }; + + function formatPendingTasksAsString(tasks) { + var result = []; + angular.forEach(tasks, function(task) { + result.push('{id: ' + task.id + ', ' + 'time: ' + task.time + '}'); + }); + + return result.join(', '); + } + + return $delegate; +}; + +/** + * + */ +angular.mock.$RootElementProvider = function() { + this.$get = function() { + return angular.element('
    '); + }; +}; + +/** + * @ngdoc overview + * @name ngMock + * @description + * + * # ngMock + * + * The `ngMock` module providers support to inject and mock Angular services into unit tests. + * In addition, ngMock also extends various core ng services such that they can be + * inspected and controlled in a synchronous manner within test code. + * + * {@installModule mocks} + * + *
    + * + */ +angular.module('ngMock', ['ng']).provider({ + $browser: angular.mock.$BrowserProvider, + $exceptionHandler: angular.mock.$ExceptionHandlerProvider, + $log: angular.mock.$LogProvider, + $interval: angular.mock.$IntervalProvider, + $httpBackend: angular.mock.$HttpBackendProvider, + $rootElement: angular.mock.$RootElementProvider +}).config(['$provide', function($provide) { + $provide.decorator('$timeout', angular.mock.$TimeoutDecorator); +}]); + +/** + * @ngdoc overview + * @name ngMockE2E + * @description + * + * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing. + * Currently there is only one mock present in this module - + * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock. + */ +angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) { + $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator); +}]); + +/** + * @ngdoc object + * @name ngMockE2E.$httpBackend + * @description + * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of + * applications that use the {@link ng.$http $http service}. + * + * *Note*: For fake http backend implementation suitable for unit testing please see + * {@link ngMock.$httpBackend unit-testing $httpBackend mock}. + * + * This implementation can be used to respond with static or dynamic responses via the `when` api + * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the + * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch + * templates from a webserver). + * + * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application + * is being developed with the real backend api replaced with a mock, it is often desirable for + * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch + * templates or static files from the webserver). To configure the backend with this behavior + * use the `passThrough` request handler of `when` instead of `respond`. + * + * Additionally, we don't want to manually have to flush mocked out requests like we do during unit + * testing. For this reason the e2e $httpBackend automatically flushes mocked out requests + * automatically, closely simulating the behavior of the XMLHttpRequest object. + * + * To setup the application to run with this http backend, you have to create a module that depends + * on the `ngMockE2E` and your application modules and defines the fake backend: + * + *
    + *   myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
    + *   myAppDev.run(function($httpBackend) {
    + *     phones = [{name: 'phone1'}, {name: 'phone2'}];
    + *
    + *     // returns the current list of phones
    + *     $httpBackend.whenGET('/phones').respond(phones);
    + *
    + *     // adds a new phone to the phones array
    + *     $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
    + *       phones.push(angular.fromJson(data));
    + *     });
    + *     $httpBackend.whenGET(/^\/templates\//).passThrough();
    + *     //...
    + *   });
    + * 
    + * + * Afterwards, bootstrap your app with this new module. + */ + +/** + * @ngdoc method + * @name ngMockE2E.$httpBackend#when + * @methodOf ngMockE2E.$httpBackend + * @description + * Creates a new backend definition. + * + * @param {string} method HTTP method. + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp)=} data HTTP request body. + * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header + * object and returns true if the headers match the current definition. + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that + * control how a matched request is handled. + * + * - respond – + * `{function([status,] data[, headers])|function(function(method, url, data, headers)}` + * – The respond method takes a set of static data to be returned or a function that can return + * an array containing response status (number), response data (string) and response headers + * (Object). + * - passThrough – `{function()}` – Any request matching a backend definition with `passThrough` + * handler, will be pass through to the real backend (an XHR request will be made to the + * server. + */ + +/** + * @ngdoc method + * @name ngMockE2E.$httpBackend#whenGET + * @methodOf ngMockE2E.$httpBackend + * @description + * Creates a new backend definition for GET requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that + * control how a matched request is handled. + */ + +/** + * @ngdoc method + * @name ngMockE2E.$httpBackend#whenHEAD + * @methodOf ngMockE2E.$httpBackend + * @description + * Creates a new backend definition for HEAD requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that + * control how a matched request is handled. + */ + +/** + * @ngdoc method + * @name ngMockE2E.$httpBackend#whenDELETE + * @methodOf ngMockE2E.$httpBackend + * @description + * Creates a new backend definition for DELETE requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that + * control how a matched request is handled. + */ + +/** + * @ngdoc method + * @name ngMockE2E.$httpBackend#whenPOST + * @methodOf ngMockE2E.$httpBackend + * @description + * Creates a new backend definition for POST requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp)=} data HTTP request body. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that + * control how a matched request is handled. + */ + +/** + * @ngdoc method + * @name ngMockE2E.$httpBackend#whenPUT + * @methodOf ngMockE2E.$httpBackend + * @description + * Creates a new backend definition for PUT requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp)=} data HTTP request body. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that + * control how a matched request is handled. + */ + +/** + * @ngdoc method + * @name ngMockE2E.$httpBackend#whenPATCH + * @methodOf ngMockE2E.$httpBackend + * @description + * Creates a new backend definition for PATCH requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @param {(string|RegExp)=} data HTTP request body. + * @param {(Object|function(Object))=} headers HTTP headers. + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that + * control how a matched request is handled. + */ + +/** + * @ngdoc method + * @name ngMockE2E.$httpBackend#whenJSONP + * @methodOf ngMockE2E.$httpBackend + * @description + * Creates a new backend definition for JSONP requests. For more info see `when()`. + * + * @param {string|RegExp} url HTTP url. + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that + * control how a matched request is handled. + */ +angular.mock.e2e = {}; +angular.mock.e2e.$httpBackendDecorator = + ['$rootScope', '$delegate', '$browser', createHttpBackendMock]; + + +angular.mock.clearDataCache = function() { + var key, + cache = angular.element.cache; + + for(key in cache) { + if (Object.prototype.hasOwnProperty.call(cache,key)) { + var handle = cache[key].handle; + + handle && angular.element(handle.elem).off(); + delete cache[key]; + } + } +}; + + + +if(window.jasmine || window.mocha) { + + var currentSpec = null, + isSpecRunning = function() { + return currentSpec && (window.mocha || currentSpec.queue.running); + }; + + + beforeEach(function() { + currentSpec = this; + }); + + afterEach(function() { + var injector = currentSpec.$injector; + + currentSpec.$injector = null; + currentSpec.$modules = null; + currentSpec = null; + + if (injector) { + injector.get('$rootElement').off(); + injector.get('$browser').pollFns.length = 0; + } + + angular.mock.clearDataCache(); + + // clean up jquery's fragment cache + angular.forEach(angular.element.fragments, function(val, key) { + delete angular.element.fragments[key]; + }); + + MockXhr.$$lastInstance = null; + + angular.forEach(angular.callbacks, function(val, key) { + delete angular.callbacks[key]; + }); + angular.callbacks.counter = 0; + }); + + /** + * @ngdoc function + * @name angular.mock.module + * @description + * + * *NOTE*: This function is also published on window for easy access.
    + * + * This function registers a module configuration code. It collects the configuration information + * which will be used when the injector is created by {@link angular.mock.inject inject}. + * + * See {@link angular.mock.inject inject} for usage example + * + * @param {...(string|Function|Object)} fns any number of modules which are represented as string + * aliases or as anonymous module initialization functions. The modules are used to + * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an + * object literal is passed they will be register as values in the module, the key being + * the module name and the value being what is returned. + */ + window.module = angular.mock.module = function() { + var moduleFns = Array.prototype.slice.call(arguments, 0); + return isSpecRunning() ? workFn() : workFn; + ///////////////////// + function workFn() { + if (currentSpec.$injector) { + throw new Error('Injector already created, can not register a module!'); + } else { + var modules = currentSpec.$modules || (currentSpec.$modules = []); + angular.forEach(moduleFns, function(module) { + if (angular.isObject(module) && !angular.isArray(module)) { + modules.push(function($provide) { + angular.forEach(module, function(value, key) { + $provide.value(key, value); + }); + }); + } else { + modules.push(module); + } + }); + } + } + }; + + /** + * @ngdoc function + * @name angular.mock.inject + * @description + * + * *NOTE*: This function is also published on window for easy access.
    + * + * The inject function wraps a function into an injectable function. The inject() creates new + * instance of {@link AUTO.$injector $injector} per test, which is then used for + * resolving references. + * + * + * ## Resolving References (Underscore Wrapping) + * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this + * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable + * that is declared in the scope of the `describe()` block. Since we would, most likely, want + * the variable to have the same name of the reference we have a problem, since the parameter + * to the `inject()` function would hide the outer variable. + * + * To help with this, the injected parameters can, optionally, be enclosed with underscores. + * These are ignored by the injector when the reference name is resolved. + * + * For example, the parameter `_myService_` would be resolved as the reference `myService`. + * Since it is available in the function body as _myService_, we can then assign it to a variable + * defined in an outer scope. + * + * ``` + * // Defined out reference variable outside + * var myService; + * + * // Wrap the parameter in underscores + * beforeEach( inject( function(_myService_){ + * myService = _myService_; + * })); + * + * // Use myService in a series of tests. + * it('makes use of myService', function() { + * myService.doStuff(); + * }); + * + * ``` + * + * See also {@link angular.mock.module angular.mock.module} + * + * ## Example + * Example of what a typical jasmine tests looks like with the inject method. + *
    +   *
    +   *   angular.module('myApplicationModule', [])
    +   *       .value('mode', 'app')
    +   *       .value('version', 'v1.0.1');
    +   *
    +   *
    +   *   describe('MyApp', function() {
    +   *
    +   *     // You need to load modules that you want to test,
    +   *     // it loads only the "ng" module by default.
    +   *     beforeEach(module('myApplicationModule'));
    +   *
    +   *
    +   *     // inject() is used to inject arguments of all given functions
    +   *     it('should provide a version', inject(function(mode, version) {
    +   *       expect(version).toEqual('v1.0.1');
    +   *       expect(mode).toEqual('app');
    +   *     }));
    +   *
    +   *
    +   *     // The inject and module method can also be used inside of the it or beforeEach
    +   *     it('should override a version and test the new version is injected', function() {
    +   *       // module() takes functions or strings (module aliases)
    +   *       module(function($provide) {
    +   *         $provide.value('version', 'overridden'); // override version here
    +   *       });
    +   *
    +   *       inject(function(version) {
    +   *         expect(version).toEqual('overridden');
    +   *       });
    +   *     });
    +   *   });
    +   *
    +   * 
    + * + * @param {...Function} fns any number of functions which will be injected using the injector. + */ + window.inject = angular.mock.inject = function() { + var blockFns = Array.prototype.slice.call(arguments, 0); + var errorForStack = new Error('Declaration Location'); + return isSpecRunning() ? workFn() : workFn; + ///////////////////// + function workFn() { + var modules = currentSpec.$modules || []; + + modules.unshift('ngMock'); + modules.unshift('ng'); + var injector = currentSpec.$injector; + if (!injector) { + injector = currentSpec.$injector = angular.injector(modules); + } + for(var i = 0, ii = blockFns.length; i < ii; i++) { + try { + /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */ + injector.invoke(blockFns[i] || angular.noop, this); + /* jshint +W040 */ + } catch (e) { + if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack; + throw e; + } finally { + errorForStack = null; + } + } + } + }; +} + + +})(window, window.angular); diff --git a/test/lib/angular/angular-scenario.js b/test/lib/angular/angular-scenario.js new file mode 100644 index 00000000..a7e34984 --- /dev/null +++ b/test/lib/angular/angular-scenario.js @@ -0,0 +1,32287 @@ +/*! + * jQuery JavaScript Library v1.10.2 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2013-07-03T13:48Z + */ +(function( window, undefined ) {'use strict'; + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +// + +var + // The deferred used on DOM ready + readyList, + + // A central reference to the root jQuery(document) + rootjQuery, + + // Support: IE<10 + // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined` + core_strundefined = typeof undefined, + + // Use the correct document accordingly with window argument (sandbox) + location = window.location, + document = window.document, + docElem = document.documentElement, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // [[Class]] -> type pairs + class2type = {}, + + // List of deleted data cache ids, so we can reuse them + core_deletedIds = [], + + core_version = "1.10.2", + + // Save a reference to some core methods + core_concat = core_deletedIds.concat, + core_push = core_deletedIds.push, + core_slice = core_deletedIds.slice, + core_indexOf = core_deletedIds.indexOf, + core_toString = class2type.toString, + core_hasOwn = class2type.hasOwnProperty, + core_trim = core_version.trim, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Used for matching numbers + core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, + + // Used for splitting on whitespace + core_rnotwhite = /\S+/g, + + // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }, + + // The ready event handler + completed = function( event ) { + + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); + jQuery.ready(); + } + }, + // Clean-up method for dom ready events + detach = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: core_version, + + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return core_slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; + }, + + slice: function() { + return this.pushStack( core_slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: core_push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), + + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + /* jshint eqeqeq: false */ + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + if ( obj == null ) { + return String( obj ); + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ core_toString.call(obj) ] || "object" : + typeof obj; + }, + + isPlainObject: function( obj ) { + var key; + + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !core_hasOwn.call(obj, "constructor") && + !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Support: IE<9 + // Handle iteration over inherited properties before own properties. + if ( jQuery.support.ownLast ) { + for ( key in obj ) { + return core_hasOwn.call( obj, key ); + } + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + // data: string of html + // context (optional): If specified, the fragment will be created in this context, defaults to document + // keepScripts (optional): If true, will include scripts passed in the html string + parseHTML: function( data, context, keepScripts ) { + if ( !data || typeof data !== "string" ) { + return null; + } + if ( typeof context === "boolean" ) { + keepScripts = context; + context = false; + } + context = context || document; + + var parsed = rsingleTag.exec( data ), + scripts = !keepScripts && []; + + // Single tag + if ( parsed ) { + return [ context.createElement( parsed[1] ) ]; + } + + parsed = jQuery.buildFragment( [ data ], context, scripts ); + if ( scripts ) { + jQuery( scripts ).remove(); + } + return jQuery.merge( [], parsed.childNodes ); + }, + + parseJSON: function( data ) { + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + if ( data === null ) { + return data; + } + + if ( typeof data === "string" ) { + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + if ( data ) { + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + } + } + } + + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: core_trim && !core_trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + core_trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + core_push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( core_indexOf ) { + return core_indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var l = second.length, + i = first.length, + j = 0; + + if ( typeof l === "number" ) { + for ( ; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var retVal, + ret = [], + i = 0, + length = elems.length; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return core_concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = core_slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations. + // Note: this method belongs to the css module but it's needed here for the support module. + // If support gets modularized, this method should be moved back to the css module. + swap: function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; + } +}); + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || type !== "function" && + ( length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj ); +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); +/*! + * Sizzle CSS Selector Engine v1.10.2 + * http://sizzlejs.com/ + * + * Copyright 2013 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2013-07-03 + */ +(function( window, undefined ) { + +var i, + support, + cachedruns, + Expr, + getText, + isXML, + compile, + outermostContext, + sortInput, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + hasDuplicate = false, + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + return 0; + }, + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments quoted, + // then not containing pseudos/brackets, + // then attribute selectors/non-parenthetical expressions, + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rsibling = new RegExp( whitespace + "*[+~]" ), + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + // BMP codepoint + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( documentIsHTML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // QSA path + if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + nid = old = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && context.parentNode || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key += " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = attrs.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Detect xml + * @param {Element|Object} elem An element or a document + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var doc = node ? node.ownerDocument || node : preferredDoc, + parent = doc.defaultView; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsHTML = !isXML( doc ); + + // Support: IE>8 + // If iframe document is assigned to "document" variable and if iframe has been reloaded, + // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 + // IE6-8 do not support the defaultView property so parent will be undefined + if ( parent && parent.attachEvent && parent !== parent.top ) { + parent.attachEvent( "onbeforeunload", function() { + setDocument(); + }); + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if getElementsByClassName can be trusted + support.getElementsByClassName = assert(function( div ) { + div.innerHTML = "
    "; + + // Support: Safari<4 + // Catch class over-caching + div.firstChild.className = "i"; + // Support: Opera<10 + // Catch gEBCN failure to find non-leading classes + return div.getElementsByClassName("i").length === 2; + }); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !doc.getElementsByName || !doc.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && documentIsHTML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + + // Support: Opera 10-12/IE8 + // ^= $= *= and empty values + // Should not select anything + // Support: Windows 8 Native Apps + // The type attribute is restricted during .innerHTML assignment + var input = doc.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "t", "" ); + + if ( div.querySelectorAll("[t^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = docElem.compareDocumentPosition ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b ); + + if ( compare ) { + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === doc || contains(preferredDoc, a) ) { + return -1; + } + if ( b === doc || contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } + + // Not directly comparable, sort on existence of method + return a.compareDocumentPosition ? -1 : 1; + } : + function( a, b ) { + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Parentless nodes are either documents or disconnected + } else if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return doc; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [elem] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val === undefined ? + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null : + val; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + for ( ; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (see #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[5] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] && match[4] !== undefined ) { + match[2] = match[4]; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), + // not comment, processing instructions, or others + // Thanks to Diego Perini for the nodeName shortcut + // Greater than "@" means alpha characters (specifically not starting with "#" or "?") + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( tokens = [] ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var data, cache, outerCache, + dirkey = dirruns + " " + doneName; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { + if ( (data = cache[1]) === true || data === cachedruns ) { + return data === true; + } + } else { + cache = outerCache[ dir ] = [ dirkey ]; + cache[1] = matcher( elem, context, xml ) || cachedruns; + if ( cache[1] === true ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + // A counter to specify which element is currently being matched + var matcherCachedRuns = 0, + bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, expandContext ) { + var elem, j, matcher, + setMatched = [], + matchedCount = 0, + i = "0", + unmatched = seed && [], + outermost = expandContext != null, + contextBackup = outermostContext, + // We must always have either seed elements or context + elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); + + if ( outermost ) { + outermostContext = context !== document && context; + cachedruns = matcherCachedRuns; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + for ( ; (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + cachedruns = ++matcherCachedRuns; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function select( selector, context, results, seed ) { + var i, tokens, token, type, find, + match = tokenize( selector ); + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + } + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && context.parentNode || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + !documentIsHTML, + results, + rsibling.test( selector ) + ); + return results; +} + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome<14 +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + elem[ name ] === true ? name.toLowerCase() : null; + } + }); +} + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})( window ); +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + firingLength = 0; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( list && ( !fired || stack ) ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var action = tuple[ 0 ], + fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = core_slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; + if( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); +jQuery.support = (function( support ) { + + var all, a, input, select, fragment, opt, eventName, isSupported, i, + div = document.createElement("div"); + + // Setup + div.setAttribute( "className", "t" ); + div.innerHTML = "
    a"; + + // Finish early in limited (non-browser) environments + all = div.getElementsByTagName("*") || []; + a = div.getElementsByTagName("a")[ 0 ]; + if ( !a || !a.style || !all.length ) { + return support; + } + + // First batch of tests + select = document.createElement("select"); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName("input")[ 0 ]; + + a.style.cssText = "top:1px;float:left;opacity:.5"; + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + support.getSetAttribute = div.className !== "t"; + + // IE strips leading whitespace when .innerHTML is used + support.leadingWhitespace = div.firstChild.nodeType === 3; + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + support.tbody = !div.getElementsByTagName("tbody").length; + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + support.htmlSerialize = !!div.getElementsByTagName("link").length; + + // Get the style information from getAttribute + // (IE uses .cssText instead) + support.style = /top/.test( a.getAttribute("style") ); + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + support.hrefNormalized = a.getAttribute("href") === "/a"; + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + support.opacity = /^0.5/.test( a.style.opacity ); + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + support.cssFloat = !!a.style.cssFloat; + + // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) + support.checkOn = !!input.value; + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + support.optSelected = opt.selected; + + // Tests for enctype support on a form (#6743) + support.enctype = !!document.createElement("form").enctype; + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + support.html5Clone = document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>"; + + // Will be defined later + support.inlineBlockNeedsLayout = false; + support.shrinkWrapBlocks = false; + support.pixelPosition = false; + support.deleteExpando = true; + support.noCloneEvent = true; + support.reliableMarginRight = true; + support.boxSizingReliable = true; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Support: IE<9 + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + // Check if we can trust getAttribute("value") + input = document.createElement("input"); + input.setAttribute( "value", "" ); + support.input = input.getAttribute( "value" ) === ""; + + // Check if an input maintains its value after becoming a radio + input.value = "t"; + input.setAttribute( "type", "radio" ); + support.radioValue = input.value === "t"; + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "checked", "t" ); + input.setAttribute( "name", "t" ); + + fragment = document.createDocumentFragment(); + fragment.appendChild( input ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event) + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) + for ( i in { submit: true, change: true, focusin: true }) { + div.setAttribute( eventName = "on" + i, "t" ); + + support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false; + } + + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + // Support: IE<9 + // Iteration over object's inherited properties before its own. + for ( i in jQuery( support ) ) { + break; + } + support.ownLast = i !== "0"; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, marginDiv, tds, + divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + container = document.createElement("div"); + container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; + + body.appendChild( container ).appendChild( div ); + + // Support: IE8 + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + div.innerHTML = "
    t
    "; + tds = div.getElementsByTagName("td"); + tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Support: IE8 + // Check if empty table cells still have offsetWidth/Height + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check box-sizing and margin behavior. + div.innerHTML = ""; + div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; + + // Workaround failing boxSizing test due to offsetWidth returning wrong value + // with some non-1 values of body zoom, ticket #13543 + jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() { + support.boxSizing = div.offsetWidth === 4; + }); + + // Use window.getComputedStyle because jsdom on node.js will break without it. + if ( window.getComputedStyle ) { + support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; + support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. (#3333) + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + marginDiv = div.appendChild( document.createElement("div") ); + marginDiv.style.cssText = div.style.cssText = divReset; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + + support.reliableMarginRight = + !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); + } + + if ( typeof div.style.zoom !== core_strundefined ) { + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.innerHTML = ""; + div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Support: IE6 + // Check if elements with layout shrink-wrap their children + div.style.display = "block"; + div.innerHTML = "
    "; + div.firstChild.style.width = "5px"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + + if ( support.inlineBlockNeedsLayout ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); + + // Null elements to avoid leaks in IE + container = div = tds = marginDiv = null; + }); + + // Null elements to avoid leaks in IE + all = select = fragment = opt = a = input = null; + + return support; +})({}); + +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rmultiDash = /([A-Z])/g; + +function internalData( elem, name, data, pvt /* Internal Use Only */ ){ + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var ret, thisCache, + internalKey = jQuery.expando, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + id = elem[ internalKey ] = core_deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + // Avoid exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( typeof name === "string" ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } else { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + i = name.length; + while ( i-- ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + /* jshint eqeqeq: false */ + } else if ( jQuery.support.deleteExpando || cache != cache.window ) { + /* jshint eqeqeq: true */ + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } +} + +jQuery.extend({ + cache: {}, + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "applet": true, + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + // Do not set data on non-element because it will not be cleared (#8335). + if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { + return false; + } + + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; + + // nodes accept data unless otherwise specified; rejection can be conditional + return !noData || noData !== true && elem.getAttribute("classid") === noData; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var attrs, name, + data = null, + i = 0, + elem = this[0]; + + // Special expections of .data basically thwart jQuery.access, + // so implement the relevant behavior ourselves + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attrs = elem.attributes; + for ( ; i < attrs.length; i++ ) { + name = attrs[i].name; + + if ( name.indexOf("data-") === 0 ) { + name = jQuery.camelCase( name.slice(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + return arguments.length > 1 ? + + // Sets one value + this.each(function() { + jQuery.data( this, key, value ); + }) : + + // Gets one value + // Try to fetch any internally stored data first + elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null; + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var nodeHook, boolHook, + rclass = /[\t\r\n\f]/g, + rreturn = /\r/g, + rfocusable = /^(?:input|select|textarea|button|object)$/i, + rclickable = /^(?:a|area)$/i, + ruseDefault = /^(?:checked|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + getSetInput = jQuery.support.input; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call( this, j, this.className ) ); + }); + } + + if ( proceed ) { + // The disjunction here is for better compressibility (see removeClass) + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + " " + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + elem.className = jQuery.trim( cur ); + + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = arguments.length === 0 || typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call( this, j, this.className ) ); + }); + } + if ( proceed ) { + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + "" + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + elem.className = value ? jQuery.trim( cur ) : ""; + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + classNames = value.match( core_rnotwhite ) || []; + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( type === core_strundefined || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // If the element has a class name or if we're passed "false", + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var ret, hooks, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // Use proper attribute retrieval(#6932, #12072) + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + elem.text; + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + one ? index : 0; + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // oldIE doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + // Don't return options that are disabled or in a disabled optgroup + ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && + ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) { + optionSet = true; + } + } + + // force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attr: function( elem, name, value ) { + var hooks, ret, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === core_strundefined ) { + return jQuery.prop( elem, name, value ); + } + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + + } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, value + "" ); + return value; + } + + } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var name, propName, + i = 0, + attrNames = value && value.match( core_rnotwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( (name = attrNames[i++]) ) { + propName = jQuery.propFix[ name ] || name; + + // Boolean attributes get special treatment (#10870) + if ( jQuery.expr.match.bool.test( name ) ) { + // Set corresponding property to false + if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { + elem[ propName ] = false; + // Support: IE<9 + // Also clear defaultChecked/defaultSelected (if appropriate) + } else { + elem[ jQuery.camelCase( "default-" + name ) ] = + elem[ propName ] = false; + } + + // See #9699 for explanation of this approach (setting first, then removal) + } else { + jQuery.attr( elem, name, "" ); + } + + elem.removeAttribute( getSetAttribute ? name : propName ); + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to default in case type is set after value during creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ? + ret : + ( elem[ name ] = value ); + + } else { + return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ? + ret : + elem[ name ]; + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + return tabindex ? + parseInt( tabindex, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + -1; + } + } + } +}); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { + // IE<8 needs the *property* name + elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); + + // Use defaultChecked and defaultSelected for oldIE + } else { + elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; + } + + return name; + } +}; +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr; + + jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ? + function( elem, name, isXML ) { + var fn = jQuery.expr.attrHandle[ name ], + ret = isXML ? + undefined : + /* jshint eqeqeq: false */ + (jQuery.expr.attrHandle[ name ] = undefined) != + getter( elem, name, isXML ) ? + + name.toLowerCase() : + null; + jQuery.expr.attrHandle[ name ] = fn; + return ret; + } : + function( elem, name, isXML ) { + return isXML ? + undefined : + elem[ jQuery.camelCase( "default-" + name ) ] ? + name.toLowerCase() : + null; + }; +}); + +// fix oldIE attroperties +if ( !getSetInput || !getSetAttribute ) { + jQuery.attrHooks.value = { + set: function( elem, value, name ) { + if ( jQuery.nodeName( elem, "input" ) ) { + // Does not return so that setAttribute is also used + elem.defaultValue = value; + } else { + // Use nodeHook if defined (#1954); otherwise setAttribute is fine + return nodeHook && nodeHook.set( elem, value, name ); + } + } + }; +} + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = { + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + elem.setAttributeNode( + (ret = elem.ownerDocument.createAttribute( name )) + ); + } + + ret.value = value += ""; + + // Break association with cloned elements by also using setAttribute (#9646) + return name === "value" || value === elem.getAttribute( name ) ? + value : + undefined; + } + }; + jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords = + // Some attributes are constructed with empty-string values when not defined + function( elem, name, isXML ) { + var ret; + return isXML ? + undefined : + (ret = elem.getAttributeNode( name )) && ret.value !== "" ? + ret.value : + null; + }; + jQuery.valHooks.button = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + return ret && ret.specified ? + ret.value : + undefined; + }, + set: nodeHook.set + }; + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + set: function( elem, value, name ) { + nodeHook.set( elem, value === "" ? false : value, name ); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }; + }); +} + + +// Some attributes require a special call on IE +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !jQuery.support.hrefNormalized ) { + // href/src property should get the full normalized URL (#10299/#12915) + jQuery.each([ "href", "src" ], function( i, name ) { + jQuery.propHooks[ name ] = { + get: function( elem ) { + return elem.getAttribute( name, 4 ); + } + }; + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Note: IE uppercases css property names, but if we were to .toLowerCase() + // .cssText, that would destroy case senstitivity in URL's, like in "background" + return elem.style.cssText || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }; +} + +jQuery.each([ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +}); + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }; + if ( !jQuery.support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + // Support: Webkit + // "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + }; + } +}); +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = core_hasOwn.call( event, "type" ) ? event.type : event, + namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && + jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = core_slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + /* jshint eqeqeq: false */ + for ( ; cur != this; cur = cur.parentNode || this ) { + /* jshint eqeqeq: true */ + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Even when returnValue equals to undefined Firefox will still show alert + if ( event.result !== undefined ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === core_strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); +var isSimple = /^.[^:#\[\.,]*$/, + rparentsprev = /^(?:parents|prev(?:Until|All))/, + rneedsContext = jQuery.expr.match.needsContext, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var i, + ret = [], + self = this, + len = self.length; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector || [], true) ); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector || [], false) ); + }, + + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + ret = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { + // Always skip document fragments + if ( cur.nodeType < 11 && (pos ? + pos.index(cur) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector(cur, selectors)) ) { + + cur = ret.push( cur ); + break; + } + } + } + + return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( jQuery.unique(all) ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + if ( this.length > 1 ) { + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + ret = jQuery.unique( ret ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + } + + return this.pushStack( ret ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + })); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + }); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + }); + + } + + if ( typeof qualifier === "string" ) { + if ( isSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; + }); +} +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /
    ", "
    " ], + tr: [ 2, "", "
    " ], + col: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
    ", "
    " ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +jQuery.fn.extend({ + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + append: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + var elem, + elems = selector ? jQuery.filter( selector, this ) : this, + i = 0; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var + // Snapshot the DOM in case .domManip sweeps something relevant into its fragment + args = jQuery.map( this, function( elem ) { + return [ elem.nextSibling, elem.parentNode ]; + }), + i = 0; + + // Make the changes, replacing each context element with the new content + this.domManip( arguments, function( elem ) { + var next = args[ i++ ], + parent = args[ i++ ]; + + if ( parent ) { + // Don't use the snapshot next if it has moved (#13810) + if ( next && next.parentNode !== parent ) { + next = this.nextSibling; + } + jQuery( this ).remove(); + parent.insertBefore( elem, next ); + } + // Allow new content to include elements from the context set + }, true ); + + // Force removal if there was no new content (e.g., from empty arguments) + return i ? this : this.remove(); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, callback, allowIntersection ) { + + // Flatten any nested arrays + args = core_concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, self.html() ); + } + self.domManip( args, callback, allowIntersection ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( this[i], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Hope ajax is available... + jQuery._evalUrl( node.src ); + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +// Support: IE<8 +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName("tbody")[0] || + elem.appendChild( elem.ownerDocument.createElement("tbody") ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + core_push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( manipulation_rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted
    , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
    " && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !jQuery.support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = jQuery.support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== core_strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + core_deletedIds.push( id ); + } + } + } + } + }, + + _evalUrl: function( url ) { + return jQuery.ajax({ + url: url, + type: "GET", + dataType: "script", + async: false, + global: false, + "throws": true + }); + } +}); +jQuery.fn.extend({ + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + } +}); +var iframe, getStyles, curCSS, + ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity\s*=\s*([^)]*)/, + rposition = /^(top|right|bottom|left)$/, + // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rmargin = /^margin/, + rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), + rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), + rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), + elemdisplay = { BODY: "block" }, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: 0, + fontWeight: 400 + }, + + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; + +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + +function isHidden( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); +} + +function showHide( elements, show ) { + var display, elem, hidden, + values = [], + index = 0, + length = elements.length; + + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + values[ index ] = jQuery._data( elem, "olddisplay" ); + display = elem.style.display; + if ( show ) { + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !values[ index ] && display === "none" ) { + elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); + } + } else { + + if ( !values[ index ] ) { + hidden = isHidden( elem ); + + if ( display && display !== "none" || !hidden ) { + jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); + } + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( index = 0; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + if ( !show || elem.style.display === "none" || elem.style.display === "" ) { + elem.style.display = show ? values[ index ] || "" : "none"; + } + } + + return elements; +} + +jQuery.fn.extend({ + css: function( name, value ) { + return jQuery.access( this, function( elem, name, value ) { + var len, styles, + map = {}, + i = 0; + + if ( jQuery.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + }, + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each(function() { + if ( isHidden( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + }); + } +}); + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "columnCount": true, + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // Make sure that NaN and null values aren't set. See: #7116 + if ( value == null || type === "number" && isNaN( value ) ) { + return; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, + // but it would mean to define eight (for every problematic property) identical functions + if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { + + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var num, val, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + //convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Return, converting to number if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; + } + return val; + } +}); + +// NOTE: we've included the "window" in window.getComputedStyle +// because jsdom on node.js will break without it. +if ( window.getComputedStyle ) { + getStyles = function( elem ) { + return window.getComputedStyle( elem, null ); + }; + + curCSS = function( elem, name, _computed ) { + var width, minWidth, maxWidth, + computed = _computed || getStyles( elem ), + + // getPropertyValue is only needed for .css('filter') in IE9, see #12537 + ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, + style = elem.style; + + if ( computed ) { + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right + // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels + // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret; + }; +} else if ( document.documentElement.currentStyle ) { + getStyles = function( elem ) { + return elem.currentStyle; + }; + + curCSS = function( elem, name, _computed ) { + var left, rs, rsLeft, + computed = _computed || getStyles( elem ), + ret = computed ? computed[ name ] : undefined, + style = elem.style; + + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && style[ name ] ) { + ret = style[ name ]; + } + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + // but not position css attributes, as those are proportional to the parent element instead + // and we can't measure the parent instead because it might trigger a "stacking dolls" problem + if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { + + // Remember the original values + left = style.left; + rs = elem.runtimeStyle; + rsLeft = rs && rs.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + rs.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : ret; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + rs.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +function setPositiveNumber( elem, value, subtract ) { + var matches = rnumsplit.exec( value ); + return matches ? + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + // If we already have the right measurement, avoid augmentation + 4 : + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + // both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // at this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + // at this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // at this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var valueIsBorderBox = true, + val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + styles = getStyles( elem ), + isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, styles ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // we need the check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +// Try to determine the default display value of an element +function css_defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + // Use the already-created iframe if possible + iframe = ( iframe || + jQuery("